1{
2 stdenv,
3 lib,
4 fetchurl,
5 fetchFromGitHub,
6 cmake,
7 coreutils,
8 curl,
9 file,
10 git,
11 makeWrapper,
12 nixosTests,
13 protobuf,
14 python3,
15 ocaml,
16 ocamlPackages,
17 which,
18 debug ? false,
19}:
20stdenv.mkDerivation rec {
21 pname = "sgx-psw";
22 # Version as given in se_version.h
23 version = "2.25.100.3";
24 # Version as used in the Git tag
25 versionTag = "2.25";
26
27 src = fetchFromGitHub {
28 owner = "intel";
29 repo = "linux-sgx";
30 rev = "sgx_${versionTag}";
31 hash = "sha256-RR+vFTd9ZM6XUn3KgQeUM+xoj1Ava4zQzFYA/nfXyaw=";
32 fetchSubmodules = true;
33 };
34
35 # Extract Intel-provided, pre-built enclaves and libs.
36 postUnpack =
37 let
38 # Fetch the pre-built, Intel-signed Architectural Enclaves (AE). They help
39 # run user application enclaves, verify launch policies, produce remote
40 # attestation quotes, and do platform certification.
41 ae.prebuilt = fetchurl {
42 url = "https://download.01.org/intel-sgx/sgx-linux/${versionTag}/prebuilt_ae_${versionTag}.tar.gz";
43 hash = "sha256-Hlh96rYOyml2y50d8ASKz6U97Fl0hbGYECeZiG9nMSQ=";
44 };
45
46 # Pre-built ipp-crypto with mitigations.
47 optlib.prebuilt = fetchurl {
48 url = "https://download.01.org/intel-sgx/sgx-linux/${versionTag}/optimized_libs_${versionTag}.tar.gz";
49 hash = "sha256-7mDTaLtpOQLHQ6Fv+FWJ2k/veJZPXIcuj7kOdRtRqhg=";
50 };
51
52 # Fetch the Data Center Attestation Primitives (DCAP) platform enclaves
53 # and pre-built sgxssl.
54 dcap = rec {
55 version = "1.22";
56 filename = "prebuilt_dcap_${version}.tar.gz";
57 prebuilt = fetchurl {
58 url = "https://download.01.org/intel-sgx/sgx-dcap/${version}/linux/${filename}";
59 hash = "sha256-RTpJQ6epoAN8YQXSJUjJQ5mPaQIiQpStTWFsnspjjDQ=";
60 };
61 };
62 in
63 ''
64 # Make sure this is the right version of linux-sgx
65 grep -q '"${version}"' "$src/common/inc/internal/se_version.h" \
66 || (echo "Could not find expected version ${version} in linux-sgx source" >&2 && exit 1)
67
68 tar -xzvf ${ae.prebuilt} -C $sourceRoot/
69 tar -xzvf ${optlib.prebuilt} -C $sourceRoot/
70
71 # Make sure we use the correct version of prebuilt DCAP
72 grep -q 'ae_file_name=${dcap.filename}' "$src/external/dcap_source/QuoteGeneration/download_prebuilt.sh" \
73 || (echo "Could not find expected prebuilt DCAP ${dcap.filename} in linux-sgx source" >&2 && exit 1)
74
75 tar -xzvf ${dcap.prebuilt} -C $sourceRoot/external/dcap_source ./prebuilt/
76 tar -xzvf ${dcap.prebuilt} -C $sourceRoot/external/dcap_source/QuoteGeneration ./psw/
77 '';
78
79 patches = [
80 # There's a `make preparation` step that downloads some prebuilt binaries
81 # and applies some patches to the in-repo git submodules. This patch removes
82 # the parts that download things, since we can't do that inside the sandbox.
83 ./disable-downloads.patch
84
85 # This patch disables mtime in bundled zip file for reproducible builds.
86 #
87 # Context: The `aesm_service` binary depends on a vendored library called
88 # `CppMicroServices`. At build time, this lib creates and then bundles
89 # service resources into a zip file and then embeds this zip into the
90 # binary. Without changes, the `aesm_service` will be different after every
91 # build because the embedded zip file contents have different modified times.
92 ./cppmicroservices-no-mtime.patch
93 ];
94
95 postPatch =
96 let
97 # The base directories we want to copy headers from. The exact headers are
98 # parsed from <linux/installer/common/sdk/BOMs/sdk_base.txt>
99 bomDirsToCopyFrom = builtins.concatStringsSep "|" [
100 "common/"
101 "external/dcap_source/"
102 "external/ippcp_internal/"
103 "external/sgx-emm/"
104 "psw/"
105 "sdk/tlibcxx/"
106 ];
107 in
108 ''
109 patchShebangs \
110 external/sgx-emm/create_symlink.sh \
111 linux/installer/bin/build-installpkg.sh \
112 linux/installer/common/psw/createTarball.sh \
113 linux/installer/common/psw/install.sh
114
115 # Run sgx-sdk preparation step
116 make preparation
117
118 # Build a fake SGX_SDK directory. Normally sgx-psw depends on first building
119 # all of sgx-sdk, however we can actually build them independently by just
120 # copying a few header files and building `sgx_edger8r` separately.
121 mkdir .sgxsdk
122 export SGX_SDK="$(readlink -f .sgxsdk)"
123
124 # Parse the BOM for the headers we need, then copy them into SGX_SDK
125 # Each line in the BOM.txt looks like:
126 # <deliverydir>/...\t<installdir>/package/...\t....
127 # TODO(phlip9): hardlink?
128 sed -n -r 's:^<deliverydir>/(${bomDirsToCopyFrom})(\S+)\s<installdir>/package/(\S+)\s.*$:\1\2\n.sgxsdk/\3:p' \
129 < linux/installer/common/sdk/BOMs/sdk_base.txt \
130 | xargs --max-args=2 install -v -D
131 '';
132
133 nativeBuildInputs = [
134 cmake
135 file
136 git
137 makeWrapper
138 ocaml
139 ocamlPackages.ocamlbuild
140 python3
141 which
142 ];
143
144 buildInputs = [
145 curl
146 protobuf
147 ];
148
149 dontUseCmakeConfigure = true;
150
151 preBuild = ''
152 # Build `sgx_edger8r`, the enclave .edl -> .h file codegen tool.
153 # Then place it in `$SGX_SDK/bin` and `$SGX_SDK/bin/x64`.
154 make -C sdk/edger8r/linux
155 mkdir -p $SGX_SDK/bin/x64
156 sgx_edger8r_bin="$(readlink -f build/linux/sgx_edger8r)"
157 ln -s $sgx_edger8r_bin $SGX_SDK/bin/
158 ln -s $sgx_edger8r_bin $SGX_SDK/bin/x64/
159
160 # Add this so we can link against libsgx_urts.
161 build_dir="$(readlink -f build/linux)"
162 ln -s $build_dir $SGX_SDK/lib
163 ln -s $build_dir $SGX_SDK/lib64
164 '';
165
166 buildFlags = [ "psw_install_pkg" ] ++ lib.optionals debug [ "DEBUG=1" ];
167
168 installFlags = [
169 "-C linux/installer/common/psw/output"
170 "DESTDIR=$(TMPDIR)/install"
171 ];
172
173 postInstall = ''
174 installDir=$TMPDIR/install
175 sgxPswDir=$installDir/opt/intel/sgxpsw
176
177 mv $installDir/usr/lib64/ $out/lib/
178 ln -sr $out/lib $out/lib64
179
180 # Install udev rules to lib/udev/rules.d
181 mv $sgxPswDir/udev/ $out/lib/
182
183 # Install example AESM config
184 mkdir $out/etc/
185 mv $sgxPswDir/aesm/conf/aesmd.conf $out/etc/
186 rmdir $sgxPswDir/aesm/conf/
187
188 # Delete init service
189 rm $sgxPswDir/aesm/aesmd.conf
190
191 # Move systemd services
192 mkdir -p $out/lib/systemd/system/
193 mv $sgxPswDir/aesm/aesmd.service $out/lib/systemd/system/
194 mv $sgxPswDir/remount-dev-exec.service $out/lib/systemd/system/
195
196 # Move misc files
197 mkdir $out/share/
198 mv $sgxPswDir/licenses $out/share/
199
200 # Remove unnecessary files
201 rm $sgxPswDir/{cleanup.sh,startup.sh}
202 rm -r $sgxPswDir/scripts
203
204 # Move aesmd binaries/libraries/enclaves
205 mv $sgxPswDir/aesm/ $out/
206
207 # We absolutely MUST avoid stripping or patching these ".signed.so" SGX
208 # enclaves. Stripping would change each enclave measurement (hash of the
209 # binary).
210 #
211 # We're going to temporarily move these enclave libs to another directory
212 # until after stripping/patching in the fixupPhase.
213 mkdir $TMPDIR/enclaves
214 mv $out/aesm/*.signed.so* $TMPDIR/enclaves
215
216 mkdir $out/bin
217 makeWrapper $out/aesm/aesm_service $out/bin/aesm_service \
218 --suffix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ protobuf ]}:$out/aesm \
219 --chdir "$out/aesm"
220
221 # Make sure we didn't forget to handle any files
222 rmdir $sgxPswDir || (echo "Error: The directory $installDir still contains unhandled files: $(ls -A $installDir)" >&2 && exit 1)
223 '';
224
225 stripDebugList = [
226 "lib"
227 "bin"
228 # Also strip binaries/libs in the `aesm` directory
229 "aesm"
230 ];
231
232 postFixup = ''
233 # Move the SGX enclaves back after everything else has been stripped.
234 mv $TMPDIR/enclaves/*.signed.so* $out/aesm/
235 rmdir $TMPDIR/enclaves
236
237 # Fixup the aesmd systemd service
238 #
239 # Most—if not all—of those fixups are not relevant for NixOS as we have our own
240 # NixOS module which is based on those files without relying on them. Still, it
241 # is helpful to have properly patched versions for non-NixOS distributions.
242 echo "Fixing aesmd.service"
243 substituteInPlace $out/lib/systemd/system/aesmd.service \
244 --replace-fail '@aesm_folder@' \
245 "$out/aesm" \
246 --replace-fail 'Type=forking' \
247 'Type=simple' \
248 --replace-fail "ExecStart=$out/aesm/aesm_service" \
249 "ExecStart=$out/bin/aesm_service --no-daemon"\
250 --replace-fail "/bin/mkdir" \
251 "${coreutils}/bin/mkdir" \
252 --replace-fail "/bin/chown" \
253 "${coreutils}/bin/chown" \
254 --replace-fail "/bin/chmod" \
255 "${coreutils}/bin/chmod" \
256 --replace-fail "/bin/kill" \
257 "${coreutils}/bin/kill"
258 '';
259
260 passthru.tests = {
261 service = nixosTests.aesmd;
262 };
263
264 meta = {
265 description = "Intel SGX Architectural Enclave Service Manager";
266 homepage = "https://github.com/intel/linux-sgx";
267 maintainers = with lib.maintainers; [
268 phlip9
269 veehaitch
270 citadelcore
271 ];
272 platforms = [ "x86_64-linux" ];
273 license = [ lib.licenses.bsd3 ];
274 };
275}