diff options
| -rw-r--r-- | .github/workflows/nix.yml | 59 | ||||
| -rw-r--r-- | README.md | 32 | ||||
| -rw-r--r-- | flake.nix | 81 | ||||
| -rw-r--r-- | nix/fetch_releases.py | 149 |
4 files changed, 176 insertions, 145 deletions
diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 71efe06..9c3ff62 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -50,3 +50,62 @@ jobs: - name: List library run: nix run ".?submodules=1#${{ matrix.library }}.default" -- list-libs + + reader: + runs-on: ubuntu-latest + permissions: + contents: read + + name: Build reader + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-tags: true + fetch-depth: -1 + + - uses: DeterminateSystems/nix-installer-action@v13 + with: + diagnostic-endpoint: "" + + - uses: DeterminateSystems/magic-nix-cache-action@v7 + with: + diagnostic-endpoint: "" + + - name: Build reader + run: | + nix build ".?submodules=1#reader" + + - name: Show reader --help + run: | + nix run ".?submodules=1#reader" -- --help + + applet: + runs-on: ubuntu-latest + permissions: + contents: read + + strategy: + matrix: + sdk: [ "222", "305", "320", "All" ] + fail-fast: false + + name: Build applet ${{ matrix.sdk }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-tags: true + fetch-depth: -1 + + - uses: DeterminateSystems/nix-installer-action@v13 + with: + diagnostic-endpoint: "" + + - uses: DeterminateSystems/magic-nix-cache-action@v7 + with: + diagnostic-endpoint: "" + + - name: Build applet + run: | + nix build ".?submodules=1#applet${{ matrix.sdk }}" @@ -348,21 +348,41 @@ nix build "#lib.openssl.v331" # To build a shim using a given version of a library (example mbedTLS 3.5): nix build "#shim.mbedtls.v35" # To build ECTesterStandalone.jar with a given version of a library (example libgcrypt 1.9.4): -nix build "?submodules=1#gcrypt.v194" +nix build ".?submodules=1#gcrypt.v194" # The available versions of the libraries are in the nix/*_pkg_versions.json files. # The "default" version always points to the most recent version. # To build ECTesterStandalone with all the libraries in default versions: -nix build "?submodules=1#" +nix build ".?submodules=1#" ``` -Each of the build steps above puts (symlinks really) its results into `./result` directory. -However, subsequent builds then replace that with their own results. To run ECTesterStandalone -with a given library version and arguments do: +Each of the build steps above puts (symlinks really) its results into `./result` directory (use `-o/--out-link {path}` +to change that directory). However, subsequent builds then replace that with their own results. To run +ECTesterStandalone with a given library version and arguments do: ```shell # This runs the default test-suite agains LibreSSL 3.9.2 -nix run "?submodules=1#libressl.v392" -- test default LibreSSL +nix run ".?submodules=1#libressl.v392" -- test default LibreSSL +``` + +To build the JavaCard applets: +```shell +nix build ".?submodules=1#applets" +# or individually +nix build ".?submodules=1#applet222" +nix build ".?submodules=1#applet305" +nix build ".?submodules=1#applet320" +``` + +To build or run the reader you can: +```shell +nix build '.?submodules=1#reader' +nix run '.?submodules=1#reader' +``` + +If needed, you can also build the `common` library: +```shell +nix build '.?submodules=1#common' ``` #### Gradle @@ -689,6 +689,73 @@ } ); + buildReader = + with pkgs; + { + jdkVersion ? jdk17_headless, + }: + gradle2nix.builders.${system}.buildGradlePackage rec { + pname = "ECTesterReader"; + version = "0.3.3"; + lockFile = ./gradle.lock; + buildJdk = pkgs.jdk_headless; + gradleBuildFlags = [ ":reader:uberJar" ]; + src = ./.; + + installPhase = '' + mkdir -p $out + cp -r reader/build $out + ''; + + nativeBuildInputs = [ makeWrapper ]; + + postFixup = '' + makeWrapper \ + ${jdk_headless}/bin/java $out/bin/${pname} \ + --add-flags "-Dstdout.encoding=UTF8 -Dstderr.encoding=UTF8 -jar $out/build/libs/${pname}.jar" + ''; + }; + + buildApplet = + with pkgs; + { + jdkVersion ? jdk8_headless, + }: + gradle2nix.builders.${system}.buildGradlePackage rec { + pname = "applet"; + # since the gradle target builds applets for multiple JC SDKs, the + # single version cannot reflet that + version = "0.3.3"; + lockFile = ./gradle.lock; + buildJdk = jdkVersion; + gradleBuildFlags = [ ":applet:buildJavaCard" ]; + src = ./.; + + installPhase = '' + mkdir --parents $out + cp --recursive applet/build/* $out + ''; + }; + + buildCommon = + with pkgs; + { + jdkVersion ? jdk17_headless, + }: + gradle2nix.builders.${system}.buildGradlePackage rec { + pname = "common"; + version = "0.3.3"; + lockFile = ./gradle.lock; + buildJdk = jdkVersion; + gradleBuildFlags = [ ":common:build" ]; + src = ./.; + + installPhase = '' + mkdir --parents $out + cp --recursive common/build/* $out + ''; + }; + defaultVersion = # Default version is the last one, aka the newest that we fetched libName: @@ -774,6 +841,20 @@ function = buildECTesterStandalone; }; + reader = buildReader { }; + common = buildCommon { }; + appletAll = pkgs.buildEnv { + name = "applets"; + paths = [ + applet222 + applet305 + applet320 + ]; + }; + applet222 = buildApplet { jdkVersion = pkgs.jdk8_headless; }; + applet305 = buildApplet { jdkVersion = pkgs.jdk8_headless; }; + applet320 = buildApplet { jdkVersion = pkgs.jdk17_headless; }; + shim = { tomcrypt = loadVersionsForShim { libName = "tomcrypt"; diff --git a/nix/fetch_releases.py b/nix/fetch_releases.py index d8e5df5..c132f3e 100644 --- a/nix/fetch_releases.py +++ b/nix/fetch_releases.py @@ -1,32 +1,17 @@ #!/usr/bin/env python3 import argparse - import json -import jinja2 import re import requests import shutil import tempfile - import pathlib import subprocess as sp - from base64 import b32encode, b32decode, b64encode, b16decode from bs4 import BeautifulSoup from packaging.version import parse as parse_version, Version -env = jinja2.Environment() - -all_versions_template = env.from_string( - """{ - buildECTesterStandalone -}: -{ {% for version in pkg_versions %} - {{ version }} {% endfor %} -}""" -) - def get_source_hash(url, unpack=False): digest_type = "sha256" @@ -48,7 +33,7 @@ def get_source_hash(url, unpack=False): return digest_sri -def serialize_versions(pkg, renders, versions): +def serialize_versions(pkg, versions): sorted_versions = { k: {kk: vv for kk, vv in v.items() if kk != "sort"} for k, v in sorted( @@ -56,10 +41,6 @@ def serialize_versions(pkg, renders, versions): ) } - # all_versions = all_versions_template.render(pkg_versions=renders).strip() - # with open(f"./nix/{pkg}_pkg_versions.nix", "w") as handle: - # handle.write(all_versions) - with open(f"./nix/{pkg}_pkg_versions.json", "w") as handle: json.dump(sorted_versions, handle, indent=4) @@ -72,13 +53,6 @@ def fetch_botan(): resp = requests.get(release_list) soup = BeautifulSoup(resp.content, "html.parser") - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; source_extension="{{ ext }}"; hash="{{ digest }}"; }; - };""" - ) - - renders = [] versions = {} for link in soup.find_all("a"): if link.text.startswith("Botan") and not link.text.endswith(".asc"): @@ -100,21 +74,13 @@ def fetch_botan(): flat_version = f"v{match['major']}{match['minor']}{match['patch']}" print(f"{version}:{digest}") - rendered = single_version_template.render( - pkg=pkg, - digest=digest, - ext=ext, - flat_version=flat_version, - version=version, - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "source_extension": ext, "hash": digest, "sort": parse_version(version), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_cryptopp(): @@ -129,7 +95,6 @@ def fetch_cryptopp(): {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; };""" ) - renders = [] versions = {} for release in resp.json(): if not release["draft"] and not release["prerelease"]: @@ -140,19 +105,12 @@ def fetch_cryptopp(): digest = get_source_hash(download_url, unpack=True) print(f"{underscored_version}:{digest}") - rendered = single_version_template.render( - pkg=pkg, - digest=digest, - flat_version=flat_version, - version=underscored_version, - ).strip() - renders.append(rendered) versions[flat_version] = { "version": underscored_version, "hash": digest, "sort": parse_version(underscored_version.replace("_", ".")), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_openssl(): @@ -186,12 +144,6 @@ def fetch_openssl(): ) ) - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; - };""" - ) - renders = [] versions = {} for tag in tags: if tag.startswith("OpenSSL_"): @@ -223,12 +175,7 @@ def fetch_openssl(): "hash": digest, "sort": parse_version(sort_version), } - - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=flat_version, version=dotted_version - ).strip() - renders.append(rendered) - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_tomcrypt(): @@ -243,53 +190,32 @@ def fetch_gcrypt(): resp = requests.get(release_list) soup = BeautifulSoup(resp.content, "html.parser") - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; - };""" - ) - - renders = [] versions = {} for link in soup.find_all("a"): if link.text.startswith("libgcrypt") and link.text.endswith("tar.bz2"): download_link = download_url.format(version=link["href"]) - match = re.match( r"libgcrypt-(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?P<dont>_do_not_use)?\.(?P<ext>.*)", link.text, ) version = f"{match['major']}.{match['minor']}.{match['patch']}" - digest = get_source_hash(download_link) print(f"{version}:{digest}") - flat_version = f"v{match['major']}{match['minor']}{match['patch']}" if match["dont"]: flat_version += "_do_not_use" - - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=flat_version, version=version - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "hash": digest, "sort": parse_version(version), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_boringssl(): pkg = "boringssl" upto = "76bb1411acf5cf6935586182a3a037d372ed1636" - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { rev="{{ rev }}"; hash="{{ digest }}"; }; - };""" - ) - renders = [] versions = {} with ( tempfile.TemporaryDirectory() as repodir, @@ -302,7 +228,6 @@ def fetch_boringssl(): ) # NOTE: we need to get rid of the .git so that it is not included in the derivation hash shutil.move(repodir / ".git", gitdir) - output = sp.check_output( [ "git", @@ -315,7 +240,6 @@ def fetch_boringssl(): ] ) refs = output.decode().split("\n") - upto_index = refs.index(upto) # pick roughly every 40th commit from the "upto" commit @@ -338,13 +262,8 @@ def fetch_boringssl(): ) print(f"{i + 1: 4d}:{rev}:{digest}") abbrev_commit = str(rev[:8]) - - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=f"r{abbrev_commit}", rev=rev - ).strip() - renders.append(rendered) versions[f"r{abbrev_commit}"] = {"rev": rev, "hash": digest, "sort": i} - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_mbedtls(): @@ -355,12 +274,6 @@ def fetch_mbedtls(): release_url = f"https://api.github.com/repos/{owner}/{repo}/releases" resp = requests.get(release_url) - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; - };""" - ) - renders = [] versions = {} for release in resp.json(): if not release["draft"] and not release["prerelease"]: @@ -377,20 +290,14 @@ def fetch_mbedtls(): digest = "sha256-tSWhF8i0Tx9QSFmyDEHdd2xveZvpyd+HXR+8xYj2Syo=" else: digest = get_source_hash(download_url, unpack=True) - print(f"{version}:{digest}") - - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=flat_version, version=version - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "hash": digest, "tag": tag, "sort": parse_version(version), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_ippcp(): @@ -401,12 +308,6 @@ def fetch_ippcp(): release_url = f"https://api.github.com/repos/{owner}/{repo}/releases" resp = requests.get(release_url) - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; - };""" - ) - renders = [] versions = {} for release in resp.json(): if not release["draft"] and not release["prerelease"]: @@ -422,16 +323,12 @@ def fetch_ippcp(): digest = get_source_hash(download_url, unpack=True) print(f"{version}:{digest}") - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=flat_version, version=version - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "hash": digest, "sort": (1, parsed) if parsed.major < 2000 else (0, parsed), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_nettle(): @@ -442,12 +339,6 @@ def fetch_nettle(): release_url = f"https://api.github.com/repos/{owner}/{repo}/tags" resp = requests.get(release_url) - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; tag="{{ tag }}"; hash="{{ digest }}"; }; - };""" - ) - renders = [] versions = {} for tag in resp.json(): if tag["name"] == "release_nettle_0.2.20010617": @@ -465,21 +356,13 @@ def fetch_nettle(): digest = get_source_hash(download_url, unpack=False) print(f"{version}:{digest}") - rendered = single_version_template.render( - pkg=pkg, - digest=digest, - flat_version=flat_version, - tag=tag["name"], - version=version, - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "tag": tag["name"], "hash": digest, "sort": parse_version(version), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def fetch_libressl(): @@ -489,13 +372,6 @@ def fetch_libressl(): resp = requests.get(release_list) soup = BeautifulSoup(resp.content, "html.parser") - single_version_template = env.from_string( - """{{ flat_version }} = buildECTesterStandalone { - {{ pkg }} = { version="{{ version }}"; hash="{{ digest }}"; }; - };""" - ) - - renders = [] versions = {} for link in soup.find_all("a"): if link.text.startswith("libressl") and link.text.endswith(".tar.gz"): @@ -509,17 +385,12 @@ def fetch_libressl(): print(f"{version}:{digest}") # NOTE: use underscore to separate the versions? flat_version = f"v{match['major']}{match['minor']}{match['patch']}" - - rendered = single_version_template.render( - pkg=pkg, digest=digest, flat_version=flat_version, version=version - ).strip() - renders.append(rendered) versions[flat_version] = { "version": version, "hash": digest, "sort": parse_version(version), } - serialize_versions(pkg, renders, versions) + serialize_versions(pkg, versions) def main(): |
