diff --git a/ci_config.json b/ci_config.json index 4d16f0483..bbe5439f2 100644 --- a/ci_config.json +++ b/ci_config.json @@ -76,6 +76,15 @@ "boost" ] }, + "aws-c-cal": { + "build_options": [ + "aws-c-cal:tests=enabled" + ], + "alpine_packages": [ + "openssl-dev", + "openssl" + ] + }, "aws-c-common": { "build_options": [ "aws-c-common:tests=enabled" diff --git a/releases.json b/releases.json index 9800e512f..1a2c9ecd9 100644 --- a/releases.json +++ b/releases.json @@ -244,6 +244,14 @@ "0.4.1-1" ] }, + "aws-c-cal": { + "dependency_names": [ + "aws-c-cal" + ], + "versions": [ + "0.9.10-1" + ] + }, "aws-c-common": { "dependency_names": [ "aws-c-common" diff --git a/subprojects/aws-c-cal.wrap b/subprojects/aws-c-cal.wrap new file mode 100644 index 000000000..25b2fe2e8 --- /dev/null +++ b/subprojects/aws-c-cal.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = aws-c-cal-0.9.10 +source_url = https://github.com/awslabs/aws-c-cal/archive/refs/tags/v0.9.10.tar.gz +source_filename = aws-c-cal-0.9.10.tar.gz +source_hash = a41b389e942fadd599a6a0f692b75480d663f1e702c0301177f00f365e0c9b94 +patch_directory = aws-c-cal + +[provide] +dependency_names = aws-c-cal diff --git a/subprojects/packagefiles/aws-c-cal/generate_tests.py b/subprojects/packagefiles/aws-c-cal/generate_tests.py new file mode 100644 index 000000000..b6816209f --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/generate_tests.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +import sys + +# Usage: generate_tests.py +if __name__ == '__main__': + with open(sys.argv[1], 'r') as test_names: + tests = [line.strip() for line in test_names if line.strip()] + with open(sys.argv[2], 'w') as out: + out.write('/* Auto-generated file, do not edit */\n\n#include \n\n') + for name in tests: + out.write(f'extern int {name}(int argc, char **argv);\n') + out.write('\n') + out.write('int main(int argc, char **argv) {\n') + for name in tests: + out.write(f' if (strcmp(argv[1], "{name}") == 0) return {name}(argc, argv);\n') + out.write(' return 0;\n') + out.write('}\n') diff --git a/subprojects/packagefiles/aws-c-cal/include/meson.build b/subprojects/packagefiles/aws-c-cal/include/meson.build new file mode 100644 index 000000000..d8a09bc91 --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/include/meson.build @@ -0,0 +1,17 @@ +install_headers( + 'aws/cal/cal.h', + 'aws/cal/ecc.h', + 'aws/cal/ed25519.h', + 'aws/cal/exports.h', + 'aws/cal/hash.h', + 'aws/cal/hkdf.h', + 'aws/cal/hmac.h', + 'aws/cal/rsa.h', + 'aws/cal/symmetric_cipher.h', + 'aws/cal/private/der.h', + 'aws/cal/private/ecc.h', + 'aws/cal/private/opensslcrypto_common.h', + 'aws/cal/private/rsa.h', + 'aws/cal/private/symmetric_cipher_priv.h', + preserve_path: true, +) diff --git a/subprojects/packagefiles/aws-c-cal/meson.build b/subprojects/packagefiles/aws-c-cal/meson.build new file mode 100644 index 000000000..7e90b047d --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/meson.build @@ -0,0 +1,187 @@ +project( + 'aws-c-cal', + 'c', + version: '0.9.10', + meson_version: '>=0.63.0', + license: 'Apache-2.0', +) + +cc = meson.get_compiler('c') +fs = import('fs') +pkg = import('pkgconfig') + +tests_opt = get_option('tests').disable_auto_if(meson.is_subproject()) +ed25519_everywhere = get_option('ed25519_everywhere') + +public_c_args = ['-DAWS_CAL_USE_IMPORT_EXPORT=1'] +c_args = ['-DAWS_CAL_EXPORTS=1'] + +if host_machine.system() == 'windows' and host_machine.cpu_family() in [ + 'x86', + 'aarch64', +] + error('unsupported architecture: only x86_64 Windows is supported') +endif + +aws_c_common_dep = dependency('aws-c-common') +libcrypto_dep = dependency( + 'libcrypto', + version: '>=1.1', +) +ncrypt = cc.find_library( + 'ncrypt', + required: host_machine.system() == 'windows', +) + +foundation = dependency( + 'appleframeworks', + modules: ['Security', 'CoreFoundation'], + required: host_machine.system() == 'darwin', +) + +src = files( + 'source/cal.c', + 'source/der.c', + 'source/ecc.c', + 'source/ed25519.c', + 'source/hash.c', + 'source/hkdf.c', + 'source/hmac.c', + 'source/rsa.c', + 'source/shared/ref_hkdf.c', + 'source/symmetric_cipher.c', +) + +if ed25519_everywhere or host_machine.system() == 'linux' + src += files('source/shared/ed25519.c', 'source/shared/lccrypto_common.c') + c_args = ['-DAWS_USE_LIBCRYPTO_TO_SUPPORT_ED25519_EVERYWHERE'] +else + src += files('source/shared/ed25519_noop.c') +endif + +if host_machine.system() in ['cygwin', 'windows'] + src += files( + 'source/windows/bcrypt_aes.c', + 'source/windows/bcrypt_ecc.c', + 'source/windows/bcrypt_hash.c', + 'source/windows/bcrypt_hmac.c', + 'source/windows/bcrypt_platform_init.c', + 'source/windows/bcrypt_rsa.c', + ) +elif host_machine.system() == 'darwin' + src += files( + 'source/darwin/commoncrypto_aes.c', + 'source/darwin/commoncrypto_hmac.c', + 'source/darwin/commoncrypto_md5.c', + 'source/darwin/commoncrypto_platform_init.c', + 'source/darwin/commoncrypto_sha1.c', + 'source/darwin/commoncrypto_sha256.c', + 'source/darwin/commoncrypto_sha512.c', + 'source/darwin/securityframework_ecc.c', + 'source/darwin/securityframework_rsa.c', + ) +elif host_machine.system() == 'linux' + src += files( + 'source/unix/openssl_aes.c', + 'source/unix/openssl_platform_init.c', + 'source/unix/openssl_rsa.c', + 'source/unix/opensslcrypto_ecc.c', + 'source/unix/opensslcrypto_hash.c', + 'source/unix/opensslcrypto_hmac.c', + ) +else + error('Unsupported platform: ' + host_machine.system()) +endif + +inc = include_directories('include') + +libaws_c_cal = library( + 'aws-c-cal', + src, + c_args: c_args + public_c_args, + dependencies: [aws_c_common_dep, libcrypto_dep, ncrypt, foundation], + include_directories: inc, + version: meson.project_version(), +) + +aws_c_cal_dep = declare_dependency( + link_with: libaws_c_cal, + include_directories: inc, + dependencies: aws_c_common_dep, + compile_args: public_c_args, +) + +meson.override_dependency('aws-c-cal', aws_c_cal_dep) + +pkg.generate( + libaws_c_cal, + extra_cflags: public_c_args, + description: 'Aws Crypto Abstraction Layer: Cross-Platform, C99 wrapper for cryptography primitives.', +) + +subdir('include') + +generate_tests = find_program( + 'generate_tests.py', + required: tests_opt, +) +run_test = find_program( + 'run_test.py', + required: tests_opt, +) + +if generate_tests.found() and run_test.found() + test_src = files( + 'tests/aes256_test.c', + 'tests/der_test.c', + 'tests/ecc_test.c', + 'tests/ed25519_test.c', + 'tests/hkdf_test.c', + 'tests/md5_test.c', + 'tests/rsa_test.c', + 'tests/sha1_test.c', + 'tests/sha256_hmac_test.c', + 'tests/sha256_test.c', + 'tests/sha512_hmac_test.c', + 'tests/sha512_test.c', + ) + + libtestcases = static_library( + 'aws_c_cal_testcases', + test_src, + dependencies: [aws_c_cal_dep], + c_args: ['-DAWS_UNSTABLE_TESTING_API=1'], + include_directories: inc, + build_by_default: false, + ) + + # implements an approximation of cmakes create_test_sourcelist + test_harness_src = custom_target( + 'generate_test_harness', + input: 'tests.txt', + output: 'test_harness.c', + command: [generate_tests, '@INPUT@', '@OUTPUT@'], + ) + + test_harness = executable( + 'aws-c-cal-tests', + test_harness_src, + dependencies: [aws_c_cal_dep], + link_with: [libtestcases], + c_args: ['-DAWS_UNSTABLE_TESTING_API=1'], + include_directories: inc, + build_by_default: false, + ) + + names = fs.read('tests.txt').split('\n') + + foreach name : names + test( + name, + run_test, + args: [test_harness, name], + workdir: meson.current_source_dir(), + timeout: 600, + ) + endforeach +endif diff --git a/subprojects/packagefiles/aws-c-cal/meson_options.txt b/subprojects/packagefiles/aws-c-cal/meson_options.txt new file mode 100644 index 000000000..cbbf2acd4 --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/meson_options.txt @@ -0,0 +1,12 @@ +option( + 'tests', + type: 'feature', + description: 'Build aws-c-cal unit tests', +) + +option( + 'ed25519_everywhere', + type: 'boolean', + value: false, + description: 'Experimental feature to support ED25519 keygen on platforms that do not support it in os libs (i.e. win/mac)', +) diff --git a/subprojects/packagefiles/aws-c-cal/run_test.py b/subprojects/packagefiles/aws-c-cal/run_test.py new file mode 100644 index 000000000..551506fb0 --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/run_test.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +import sys + +# Usage: run_test.py [args...] +if __name__ == '__main__': + test_exe = sys.argv[1] + test_args = sys.argv[2:] + import subprocess + result = subprocess.run([test_exe] + test_args) + exitcode = result.returncode + if exitcode == 103: + exitcode = 77 # Skip code for meson + sys.exit(exitcode) diff --git a/subprojects/packagefiles/aws-c-cal/tests.txt b/subprojects/packagefiles/aws-c-cal/tests.txt new file mode 100644 index 000000000..d0276300e --- /dev/null +++ b/subprojects/packagefiles/aws-c-cal/tests.txt @@ -0,0 +1,171 @@ + +sha256_nist_test_case_1 +sha256_nist_test_case_2 +sha256_nist_test_case_3 +sha256_nist_test_case_4 +sha256_nist_test_case_5 +sha256_nist_test_case_5_truncated +sha256_nist_test_case_6 +sha256_test_invalid_buffer +sha256_test_oneshot +sha256_test_invalid_state +sha256_test_extra_buffer_space +sha512_nist_test_case_1 +sha512_nist_test_case_2 +sha512_nist_test_case_3 +sha512_nist_test_case_4 +sha512_nist_test_case_5 +sha512_nist_test_case_5_truncated +sha512_nist_test_case_6 +sha512_test_invalid_buffer +sha512_test_oneshot +sha512_test_invalid_state +sha512_test_extra_buffer_space +sha1_nist_test_case_1 +sha1_nist_test_case_2 +sha1_nist_test_case_3 +sha1_nist_test_case_4 +sha1_nist_test_case_5 +sha1_nist_test_case_5_truncated +sha1_nist_test_case_6 +sha1_test_invalid_buffer +sha1_test_oneshot +sha1_test_invalid_state +sha1_test_extra_buffer_space +md5_rfc1321_test_case_1 +md5_rfc1321_test_case_2 +md5_rfc1321_test_case_3 +md5_rfc1321_test_case_4 +md5_rfc1321_test_case_5 +md5_rfc1321_test_case_6 +md5_rfc1321_test_case_7 +md5_rfc1321_test_case_7_truncated +md5_verify_known_collision +md5_invalid_buffer_size +md5_test_invalid_state +md5_test_extra_buffer_space +sha256_hmac_rfc4231_test_case_1 +sha256_hmac_rfc4231_test_case_2 +sha256_hmac_rfc4231_test_case_3 +sha256_hmac_rfc4231_test_case_4 +sha256_hmac_rfc4231_test_case_5 +sha256_hmac_rfc4231_test_case_6 +sha256_hmac_rfc4231_test_case_7 +sha256_hmac_test_oneshot +sha256_hmac_test_invalid_buffer +sha256_hmac_test_invalid_state +sha256_hmac_test_extra_buffer_space +sha512_hmac_rfc4231_test_case_1 +sha512_hmac_rfc4231_test_case_2 +sha512_hmac_rfc4231_test_case_3 +sha512_hmac_rfc4231_test_case_4 +sha512_hmac_rfc4231_test_case_5 +sha512_hmac_rfc4231_test_case_6 +sha512_hmac_rfc4231_test_case_7 +sha512_hmac_test_oneshot +sha512_hmac_test_invalid_buffer +sha512_hmac_test_invalid_state +sha512_hmac_test_extra_buffer_space +ecdsa_p256_test_pub_key_derivation +ecdsa_p384_test_pub_key_derivation +ecdsa_p256_test_known_signing_value +ecdsa_p384_test_known_signing_value +ecdsa_test_invalid_signature +ecdsa_p256_test_key_gen +ecdsa_p384_test_key_gen +ecdsa_p256_test_key_gen_export +ecdsa_p384_test_key_gen_export +ecdsa_p256_test_import_asn1_key_pair +ecdsa_p256_test_import_asn1_pkcs8_key_pair +ecdsa_p384_test_import_asn1_key_pair +ecdsa_test_import_asn1_key_pair_public_only +ecdsa_test_import_asn1_key_pair_invalid_fails +ecdsa_test_signature_format +ecdsa_p256_test_small_coordinate_verification +ecdsa_signature_encode_helper_roundtrip +ecdsa_export_sec1_roundtrip +ecdsa_export_pkcs8_roundtrip +ecdsa_export_spki_roundtrip +rsa_encryption_roundtrip_pkcs1_from_user +rsa_encryption_roundtrip_oaep_sha256_from_user +rsa_encryption_roundtrip_oaep_sha512_from_user +rsa_signing_roundtrip_pkcs1_sha256_from_user +rsa_signing_roundtrip_pss_sha256_from_user +rsa_signing_roundtrip_pkcs1_sha1_from_user +rsa_getters +rsa_private_pkcs1_der_parsing +rsa_public_pkcs1_der_parsing +rsa_verify_signing_pkcs1_sha256 +rsa_verify_signing_pkcs1_sha1 +rsa_verify_signing_pss_sha256 +rsa_decrypt_pkcs1 +rsa_decrypt_oaep256 +rsa_decrypt_oaep512 +rsa_signing_mismatch_pkcs1_sha256 +rsa_signing_mismatch_pkcs1_sha1 +rsa_encryption_roundtrip_pkcs15_from_user_pkcs8 +aes_cbc_NIST_CBCGFSbox256_case_1 +aes_cbc_NIST_CBCVarKey256_case_254 +aes_cbc_NIST_CBCVarTxt256_case_110 +aes_cbc_NIST_CBCMMT256_case_4 +aes_cbc_NIST_CBCMMT256_case_9 +aes_cbc_test_with_generated_key_iv +aes_cbc_validate_materials_fails +aes_ctr_RFC3686_Case_7 +aes_ctr_RFC3686_Case_8 +aes_ctr_RFC3686_Case_9 +aes_ctr_test_with_generated_key_iv +aes_ctr_validate_materials_fails +gcm_NIST_gcmEncryptExtIV256_PTLen_128_Test_0 +gcm_NIST_gcmEncryptExtIV256_PTLen_104_Test_3 +gcm_NIST_gcmEncryptExtIV256_PTLen_256_Test_6 +gcm_NIST_gcmEncryptExtIV256_PTLen_408_Test_8 +gcm_256_KAT_1 +gcm_256_KAT_2 +gcm_256_KAT_3 +gcm_test_with_generated_key_iv +aes_gcm_validate_materials_fails +aes_keywrap_RFC3394_256BitKey256CekTestVector +aes_keywrap_Rfc3394_256BitKey_TestIntegrityCheckFailed +aes_keywrap_RFC3394_256BitKeyTestBadPayload +aes_keywrap_RFC3394_256BitKey128BitCekTestVector +aes_keywrap_RFC3394_256BitKey128BitCekIntegrityCheckFailedTestVector +aes_keywrap_RFC3394_256BitKey128BitCekPayloadCheckFailedTestVector +aes_keywrap_validate_materials_fails +aes_test_input_too_large +aes_test_encrypt_empty_input +aes_test_empty_input_gcm_tag_corner_cases +aes_test_gcm_tag_corner_cases +aes_test_gcm_tag_large_input_corner_cases +der_encode_integer +der_encode_integer_zero +der_encode_boolean +der_encode_null +der_encode_bit_string +der_encode_octet_string +der_encode_sequence +der_encode_set +der_decode_negative_int +der_decode_positive_int +der_decode_zero_int +der_decode_bad_length +der_decode_zero_length_int +der_roundtrip_context_specific_tags +der_decode_integer +der_decode_integer_zero +der_decode_boolean +der_decode_null +der_decode_bit_string +der_decode_octet_string +der_decode_sequence +der_decode_set +der_decode_key_pair +ecc_key_pair_random_ref_count_test +ecc_key_pair_public_ref_count_test +ecc_key_pair_asn1_ref_count_test +ecc_key_pair_private_ref_count_test +ecc_key_gen_from_private_fuzz_test +ed25519_key_pair_generate_test +hkdf_derive_test_case_1 +hkdf_derive_test_case_2 +hkdf_derive_test_case_3 \ No newline at end of file diff --git a/tools/sanity_checks.py b/tools/sanity_checks.py index c5414d63b..02f3ffffb 100755 --- a/tools/sanity_checks.py +++ b/tools/sanity_checks.py @@ -34,6 +34,11 @@ PERMITTED_FILES = {'generator.sh', 'meson.build', 'meson_options.txt', 'meson.options', 'LICENSE.build'} PER_PROJECT_PERMITTED_FILES: dict[str, set[str]] = { + 'aws-c-cal': { + 'tests.txt', + 'generate_tests.py', + 'run_test.py', + }, 'aws-c-common': { 'tests.txt', 'generate_tests.py',