pq_crypto-seal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +66 -0
- data/CHANGELOG.md +44 -0
- data/FORMAT.md +139 -0
- data/GET_STARTED.md +30 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +215 -0
- data/RELEASING.md +34 -0
- data/Rakefile +19 -0
- data/SECURITY.md +85 -0
- data/VENDORING.md +14 -0
- data/ext/pq_crypto_seal/aegis_unused_stubs.c +20 -0
- data/ext/pq_crypto_seal/extconf.rb +296 -0
- data/ext/pq_crypto_seal/pq_crypto_seal.c +390 -0
- data/ext/pq_crypto_seal/vendor/libaegis/LICENSE +21 -0
- data/ext/pq_crypto_seal/vendor/libaegis/TREE_SHA256 +1 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l.c +246 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.c +73 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.c +70 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_common.h +691 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.c +77 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.c +86 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_neon_sha3.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.c +63 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/aegis128l_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128l/implementations.h +40 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2.c +247 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.c +108 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.c +103 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.c +79 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_avx2.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_common.h +795 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.c +111 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.c +96 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/aegis128x2_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x2/implementations.h +40 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4.c +252 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.c +117 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.c +111 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.c +112 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx2.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.c +85 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_avx512.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_common.h +808 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.c +119 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.c +104 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/aegis128x4_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis128x4/implementations.h +41 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256.c +240 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_aesni.c +68 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_altivec.c +68 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_common.h +673 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_neon_aes.c +75 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_soft.c +58 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/aegis256_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256/implementations.h +39 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2.c +247 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.c +103 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.c +101 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.c +74 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_avx2.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_common.h +790 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.c +109 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.c +91 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/aegis256x2_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x2/implementations.h +41 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4.c +252 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.c +112 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_aesni.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.c +109 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_altivec.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.c +107 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx2.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.c +79 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_avx512.h +11 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_common.h +805 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.c +117 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_neon_aes.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.c +99 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/aegis256x4_soft.h +9 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/aegis256x4/implementations.h +42 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/common.c +81 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/common.h +144 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/cpu.c +378 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/cpu.h +34 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/keccak.c +187 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/keccak.h +13 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/softaes.c +338 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/common/softaes.h +69 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis.h +77 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128l.h +311 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128x2.h +313 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis128x4.h +313 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256.h +311 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256x2.h +313 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis256x4.h +313 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/include/aegis_raf.h +580 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf.c +87 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128l.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x2.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis128x4.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x2.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_aegis256x4.c +20 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_internal.h +152 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.c +268 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_merkle.h +165 -0
- data/ext/pq_crypto_seal/vendor/libaegis/src/raf/raf_variant.h +1119 -0
- data/fuzz/decrypt_fuzz.rb +119 -0
- data/lib/pq_crypto/seal/binary.rb +62 -0
- data/lib/pq_crypto/seal/core.rb +398 -0
- data/lib/pq_crypto/seal/errors.rb +15 -0
- data/lib/pq_crypto/seal/format.rb +275 -0
- data/lib/pq_crypto/seal/io.rb +336 -0
- data/lib/pq_crypto/seal/native.rb +13 -0
- data/lib/pq_crypto/seal/padding.rb +47 -0
- data/lib/pq_crypto/seal/version.rb +6 -0
- data/lib/pq_crypto/seal.rb +32 -0
- data/pq_crypto-seal.gemspec +37 -0
- data/script/vendor_libs.rb +79 -0
- data/test/aegis_vectors_test.rb +54 -0
- data/test/golden_vectors_test.rb +183 -0
- data/test/io_test.rb +125 -0
- data/test/native_test.rb +36 -0
- data/test/seal_test.rb +238 -0
- data/test/test_helper.rb +6 -0
- metadata +244 -0
data/VENDORING.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Vendored cryptography
|
|
2
|
+
|
|
3
|
+
`ext/pq_crypto_seal/vendor/libaegis/src` contains the C sources corresponding to
|
|
4
|
+
libaegis 0.10.3.
|
|
5
|
+
|
|
6
|
+
- Upstream: https://github.com/aegis-aead/libaegis
|
|
7
|
+
- Tag: `0.10.3`
|
|
8
|
+
- Tag commit: `0bb1639`
|
|
9
|
+
- Official tag archive SHA-256: `2f2682c1d08d9a5510caca1c82e3f8ea91f7085fef2ecbed0c398b2a921c79b1`
|
|
10
|
+
- License: MIT
|
|
11
|
+
|
|
12
|
+
The complete source snapshot is retained, while the Ruby extension compiles only the AEGIS-256 and common implementation files it exposes. No system libaegis is
|
|
13
|
+
loaded at runtime. Update the version, archive checksum, source snapshot, KATs,
|
|
14
|
+
and cross-backend tests together.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* pq_crypto-seal exposes only AEGIS-256. libaegis common.c initializes all
|
|
3
|
+
* optional families, so source-only builds provide no-op selectors for the
|
|
4
|
+
* families deliberately not linked into this extension.
|
|
5
|
+
*/
|
|
6
|
+
int aegis128l_pick_best_implementation(void) {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
int aegis128x2_pick_best_implementation(void) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
int aegis128x4_pick_best_implementation(void) {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
int aegis256x2_pick_best_implementation(void) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
int aegis256x4_pick_best_implementation(void) {
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "rbconfig"
|
|
6
|
+
require "shellwords"
|
|
7
|
+
|
|
8
|
+
extension_name = "pq_crypto/seal/pq_crypto_seal"
|
|
9
|
+
|
|
10
|
+
# Ruby 2.7 installations on macOS are often built against Homebrew OpenSSL 1.1.
|
|
11
|
+
# Their RbConfig can inject that old prefix into every extension build, even when
|
|
12
|
+
# OpenSSL 3 is installed separately. Select one complete OpenSSL 3 installation,
|
|
13
|
+
# remove competing OpenSSL header paths, and link the selected libcrypto by its
|
|
14
|
+
# absolute path so headers and library cannot silently come from different roots.
|
|
15
|
+
|
|
16
|
+
def command_output(*command)
|
|
17
|
+
IO.popen(command, err: File::NULL, &:read).to_s.strip
|
|
18
|
+
rescue StandardError
|
|
19
|
+
""
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def host_os
|
|
23
|
+
RbConfig::CONFIG.fetch("host_os", "")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def windows_host?
|
|
27
|
+
host_os =~ /mswin|mingw|cygwin/i
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def openssl_library_dirs(prefix)
|
|
31
|
+
dirs = Dir.glob(File.join(prefix, "lib", "*-linux-gnu"))
|
|
32
|
+
dirs.concat([File.join(prefix, "lib64"), File.join(prefix, "lib")])
|
|
33
|
+
dirs.select { |directory| File.directory?(directory) }.uniq
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def openssl_library_file(directory)
|
|
37
|
+
candidates = [
|
|
38
|
+
File.join(directory, "libcrypto.so.3"),
|
|
39
|
+
*Dir.glob(File.join(directory, "libcrypto.so.3.*")).sort,
|
|
40
|
+
File.join(directory, "libcrypto.so"),
|
|
41
|
+
File.join(directory, "libcrypto.3.dylib"),
|
|
42
|
+
*Dir.glob(File.join(directory, "libcrypto.3.*.dylib")).sort,
|
|
43
|
+
File.join(directory, "libcrypto.dylib"),
|
|
44
|
+
File.join(directory, "libcrypto.a"),
|
|
45
|
+
File.join(directory, "libcrypto.dll.a"),
|
|
46
|
+
File.join(directory, "crypto.lib")
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
path = candidates.find { |candidate| File.file?(candidate) }
|
|
50
|
+
path && File.realpath(path)
|
|
51
|
+
rescue Errno::ENOENT
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def openssl_header_major(include_directory)
|
|
56
|
+
header = File.join(include_directory, "openssl", "opensslv.h")
|
|
57
|
+
return nil unless File.file?(header)
|
|
58
|
+
|
|
59
|
+
contents = File.read(header)
|
|
60
|
+
major = contents[/^\s*#\s*define\s+OPENSSL_VERSION_MAJOR\s+(\d+)/, 1]
|
|
61
|
+
return major.to_i if major
|
|
62
|
+
|
|
63
|
+
# OpenSSL 1.x has no OPENSSL_VERSION_MAJOR. Parse the high hexadecimal nibble
|
|
64
|
+
# only to reject it cleanly; OpenSSL 3 installations always define the major.
|
|
65
|
+
number = contents[/^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+0x([0-9A-Fa-f]+)L?/, 1]
|
|
66
|
+
number ? (number.to_i(16) >> 28) & 0xF : nil
|
|
67
|
+
rescue StandardError
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def openssl_installation(include_directory, library_directory)
|
|
72
|
+
return nil unless include_directory && library_directory
|
|
73
|
+
|
|
74
|
+
include_directory = File.expand_path(include_directory)
|
|
75
|
+
library_directory = File.expand_path(library_directory)
|
|
76
|
+
return nil unless openssl_header_major(include_directory).to_i >= 3
|
|
77
|
+
|
|
78
|
+
crypto_library = openssl_library_file(library_directory)
|
|
79
|
+
return nil unless crypto_library
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
include_directory: include_directory,
|
|
83
|
+
library_directory: library_directory,
|
|
84
|
+
crypto_library: crypto_library
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def openssl_prefix_installation(prefix)
|
|
89
|
+
return nil if prefix.nil? || prefix.to_s.strip.empty?
|
|
90
|
+
|
|
91
|
+
prefix = File.expand_path(prefix.to_s.strip)
|
|
92
|
+
include_directory = File.join(prefix, "include")
|
|
93
|
+
openssl_library_dirs(prefix).each do |library_directory|
|
|
94
|
+
installation = openssl_installation(include_directory, library_directory)
|
|
95
|
+
return installation.merge(prefix: prefix) if installation
|
|
96
|
+
end
|
|
97
|
+
nil
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def argument_value(name)
|
|
101
|
+
prefix = "--#{name}"
|
|
102
|
+
ARGV.each_with_index do |argument, index|
|
|
103
|
+
return argument.split("=", 2)[1] if argument.start_with?("#{prefix}=")
|
|
104
|
+
return ARGV[index + 1] if argument == prefix && ARGV[index + 1]
|
|
105
|
+
end
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def explicit_openssl_installation
|
|
110
|
+
explicit_root = argument_value("with-openssl-dir") || ENV["OPENSSL_ROOT_DIR"] || ENV["OPENSSL_DIR"]
|
|
111
|
+
if explicit_root && !explicit_root.to_s.strip.empty?
|
|
112
|
+
installation = openssl_prefix_installation(explicit_root)
|
|
113
|
+
abort <<~MSG unless installation
|
|
114
|
+
#{explicit_root.inspect} does not point to a complete OpenSSL 3 installation.
|
|
115
|
+
|
|
116
|
+
Expected OpenSSL 3 headers below <prefix>/include/openssl and libcrypto
|
|
117
|
+
below <prefix>/lib, <prefix>/lib64, or a Linux multiarch lib directory.
|
|
118
|
+
MSG
|
|
119
|
+
return installation.merge(source: "explicit prefix")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
explicit_include = argument_value("with-openssl-include")
|
|
123
|
+
explicit_library = argument_value("with-openssl-lib")
|
|
124
|
+
return nil unless explicit_include || explicit_library
|
|
125
|
+
|
|
126
|
+
abort "Both --with-openssl-include and --with-openssl-lib are required together" unless explicit_include && explicit_library
|
|
127
|
+
installation = openssl_installation(explicit_include, explicit_library)
|
|
128
|
+
abort "Explicit OpenSSL include/lib paths do not contain a matching OpenSSL 3 headers + libcrypto pair" unless installation
|
|
129
|
+
|
|
130
|
+
installation.merge(source: "explicit include/lib")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def pkg_config_openssl_installation
|
|
134
|
+
return nil unless find_executable("pkg-config")
|
|
135
|
+
|
|
136
|
+
version = command_output("pkg-config", "--modversion", "openssl")
|
|
137
|
+
return nil if version.empty? || version.split(".").first.to_i < 3
|
|
138
|
+
|
|
139
|
+
include_directory = command_output("pkg-config", "--variable=includedir", "openssl")
|
|
140
|
+
library_directory = command_output("pkg-config", "--variable=libdir", "openssl")
|
|
141
|
+
installation = openssl_installation(include_directory, library_directory)
|
|
142
|
+
installation && installation.merge(source: "pkg-config #{version}")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def discover_openssl3_installation
|
|
146
|
+
explicit = explicit_openssl_installation
|
|
147
|
+
return explicit if explicit
|
|
148
|
+
|
|
149
|
+
candidates = []
|
|
150
|
+
if host_os =~ /darwin/i && find_executable("brew")
|
|
151
|
+
candidates << command_output("brew", "--prefix", "openssl@3")
|
|
152
|
+
candidates << command_output("brew", "--prefix", "openssl")
|
|
153
|
+
end
|
|
154
|
+
candidates.concat(
|
|
155
|
+
%w[
|
|
156
|
+
/opt/homebrew/opt/openssl@3
|
|
157
|
+
/usr/local/opt/openssl@3
|
|
158
|
+
/opt/homebrew/opt/openssl
|
|
159
|
+
/usr/local/opt/openssl
|
|
160
|
+
]
|
|
161
|
+
) if host_os =~ /darwin/i
|
|
162
|
+
|
|
163
|
+
candidates.compact.map(&:strip).reject(&:empty?).uniq.each do |prefix|
|
|
164
|
+
installation = openssl_prefix_installation(prefix)
|
|
165
|
+
return installation.merge(source: "prefix", prefix: File.expand_path(prefix)) if installation
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
pkg_config_openssl_installation ||
|
|
169
|
+
openssl_prefix_installation("/usr/local")&.merge(source: "system prefix", prefix: "/usr/local") ||
|
|
170
|
+
openssl_prefix_installation("/usr")&.merge(source: "system prefix", prefix: "/usr")
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def normalize_existing_path(path)
|
|
174
|
+
File.realpath(path)
|
|
175
|
+
rescue Errno::ENOENT
|
|
176
|
+
File.expand_path(path)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def include_paths_from_flags(flags)
|
|
180
|
+
tokens = Shellwords.split(flags.to_s)
|
|
181
|
+
paths = []
|
|
182
|
+
index = 0
|
|
183
|
+
|
|
184
|
+
while index < tokens.length
|
|
185
|
+
token = tokens[index]
|
|
186
|
+
case token
|
|
187
|
+
when "-I", "-isystem"
|
|
188
|
+
paths << tokens[index + 1] if tokens[index + 1]
|
|
189
|
+
index += 2
|
|
190
|
+
next
|
|
191
|
+
when /\A-I(.+)\z/
|
|
192
|
+
paths << Regexp.last_match(1)
|
|
193
|
+
when /\A-isystem(.+)\z/
|
|
194
|
+
paths << Regexp.last_match(1)
|
|
195
|
+
end
|
|
196
|
+
index += 1
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
paths
|
|
200
|
+
rescue ArgumentError
|
|
201
|
+
[]
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def strip_include_path(flags, path)
|
|
205
|
+
escaped = Regexp.escape(path)
|
|
206
|
+
flags.to_s
|
|
207
|
+
.gsub(/(?:\A|\s)-I\s*#{escaped}(?=\s|\z)/, " ")
|
|
208
|
+
.gsub(/(?:\A|\s)-isystem\s*#{escaped}(?=\s|\z)/, " ")
|
|
209
|
+
.strip
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def remove_competing_openssl_headers!(selected_include_directory)
|
|
213
|
+
selected = normalize_existing_path(selected_include_directory)
|
|
214
|
+
competing = [$INCFLAGS, $CPPFLAGS, $CFLAGS]
|
|
215
|
+
.flat_map { |flags| include_paths_from_flags(flags) }
|
|
216
|
+
.uniq
|
|
217
|
+
.select do |path|
|
|
218
|
+
File.file?(File.join(path, "openssl", "opensslv.h")) && normalize_existing_path(path) != selected
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
competing.each do |path|
|
|
222
|
+
$INCFLAGS = strip_include_path($INCFLAGS, path)
|
|
223
|
+
$CPPFLAGS = strip_include_path($CPPFLAGS, path)
|
|
224
|
+
$CFLAGS = strip_include_path($CFLAGS, path)
|
|
225
|
+
puts "Ignoring competing OpenSSL headers: #{path}"
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def configure_selected_openssl!(installation)
|
|
230
|
+
include_directory = installation.fetch(:include_directory)
|
|
231
|
+
library_directory = installation.fetch(:library_directory)
|
|
232
|
+
crypto_library = installation.fetch(:crypto_library)
|
|
233
|
+
|
|
234
|
+
remove_competing_openssl_headers!(include_directory)
|
|
235
|
+
|
|
236
|
+
# Do not call dir_config("openssl") here. On Ruby 2.7 it can reuse the
|
|
237
|
+
# --with-openssl-dir value from Ruby's own build and reintroduce OpenSSL 1.1.
|
|
238
|
+
$INCFLAGS = "-I#{Shellwords.escape(include_directory)} #{$INCFLAGS}".strip
|
|
239
|
+
$CPPFLAGS = "-I#{Shellwords.escape(include_directory)} #{$CPPFLAGS}".strip
|
|
240
|
+
$LIBPATH.unshift(library_directory) unless $LIBPATH.include?(library_directory)
|
|
241
|
+
$LOCAL_LIBS = "#{Shellwords.escape(crypto_library)} #{$LOCAL_LIBS}".strip
|
|
242
|
+
|
|
243
|
+
unless windows_host? || library_directory.start_with?("/usr/lib")
|
|
244
|
+
$LDFLAGS = "-Wl,-rpath,#{Shellwords.escape(library_directory)} #{$LDFLAGS}".strip
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
puts "OpenSSL source: #{installation.fetch(:source)}"
|
|
248
|
+
puts "OpenSSL prefix: #{installation[:prefix]}" if installation[:prefix]
|
|
249
|
+
puts "OpenSSL include dir: #{include_directory}"
|
|
250
|
+
puts "OpenSSL library dir: #{library_directory}"
|
|
251
|
+
puts "OpenSSL libcrypto: #{crypto_library}"
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
selected_openssl = discover_openssl3_installation
|
|
255
|
+
if selected_openssl
|
|
256
|
+
configure_selected_openssl!(selected_openssl)
|
|
257
|
+
else
|
|
258
|
+
puts "OpenSSL 3 prefix: none resolved; using compiler defaults"
|
|
259
|
+
abort "OpenSSL libcrypto is required" unless have_library("crypto")
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
%w[openssl/evp.h openssl/hmac.h openssl/rand.h openssl/crypto.h openssl/opensslv.h].each do |header|
|
|
263
|
+
abort "#{header} is required" unless have_header(header)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
if selected_openssl
|
|
267
|
+
header_major = openssl_header_major(selected_openssl.fetch(:include_directory))
|
|
268
|
+
abort "OpenSSL 3.0 or newer headers are required" unless header_major && header_major >= 3
|
|
269
|
+
puts "OpenSSL header major: #{header_major}"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
abort "rb_thread_call_without_gvl is required" unless have_func("rb_thread_call_without_gvl", "ruby/thread.h")
|
|
273
|
+
|
|
274
|
+
$CFLAGS << " -std=c11 -O3 -Wall -Wextra"
|
|
275
|
+
if ENV["PQC_SEAL_SANITIZE"] == "1"
|
|
276
|
+
$CFLAGS << " -O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined"
|
|
277
|
+
$LDFLAGS << " -fsanitize=address,undefined"
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
vendor = Pathname(__dir__).join("vendor/libaegis/src")
|
|
281
|
+
patterns = %w[
|
|
282
|
+
aegis256/*.c common/*.c
|
|
283
|
+
]
|
|
284
|
+
sources = patterns.flat_map { |pattern| Dir[vendor.join(pattern).to_s] }.sort
|
|
285
|
+
abort "vendored libaegis sources are missing" if sources.empty?
|
|
286
|
+
|
|
287
|
+
$INCFLAGS << " -I$(srcdir)/vendor/libaegis/src/include"
|
|
288
|
+
source_dirs = sources.map { |source| File.dirname(source) }.uniq
|
|
289
|
+
source_dirs.each do |directory|
|
|
290
|
+
relative = Pathname(directory).relative_path_from(Pathname(__dir__))
|
|
291
|
+
$VPATH << "$(srcdir)/#{relative}"
|
|
292
|
+
$INCFLAGS << " -I$(srcdir)/#{relative}"
|
|
293
|
+
end
|
|
294
|
+
$srcs = ["pq_crypto_seal.c", "aegis_unused_stubs.c"] + sources.map { |source| File.basename(source) }
|
|
295
|
+
|
|
296
|
+
create_makefile(extension_name)
|