diff --git a/.github/workflows/a10rest-docker-image.yml b/.github/workflows/a10rest-docker-image.yml deleted file mode 100644 index fa69897..0000000 --- a/.github/workflows/a10rest-docker-image.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Docker Image CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Build the Docker image - run: docker build --file a10rest/Dockerfile.local --tag a10rest:$(date +%s) --output type=local,dest=a10rest.build.output . - - uses: slsa-framework/github-actions-demo@v0.1 - with: - artifact_path: a10rest.build.output - output_path: a10rest.provenance - continue-on-error: true diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml deleted file mode 100644 index 4c9413b..0000000 --- a/.github/workflows/android.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: Android CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: "11" - distribution: "adopt" - cache: gradle - - name: Grant execute permission for gradlew - working-directory: ./apps/mobileattester - run: chmod +x gradlew - - - name: Run lint - working-directory: ./apps/mobileattester - run: ./gradlew lintDebug - - name: Upload html test report - uses: actions/upload-artifact@v2 - with: - name: lint.html - path: ./apps/mobileattester/app/build/reports/lint-results-debug.html - - - name: Build with Gradle - working-directory: ./apps/mobileattester - run: ./gradlew build - - test: - needs: [build] - name: Run Unit Tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: "11" - distribution: "adopt" - cache: gradle - - name: Run unit tests - working-directory: ./apps/mobileattester - run: bash ./gradlew test --stacktrace - - apk: - needs: [test] - name: Generate APK - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: set up JDK 1.8 - uses: actions/setup-java@v1 - with: - java-version: 11 - - name: Grant execute permission for gradlew - working-directory: ./apps/mobileattester - run: chmod +x gradlew - - name: Build APK - working-directory: ./apps/mobileattester - run: ./gradlew assembleDebug - - name: Upload APK - uses: actions/upload-artifact@v2 - with: - name: app - path: ./apps/mobileattester/app/build/outputs/apk/debug/app-debug.apk diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index f3d17c2..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,70 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ main ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ main ] - schedule: - - cron: '33 14 * * 5' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go', 'javascript', 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://git.io/codeql-language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # â„šī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 diff --git a/.gitignore b/.gitignore index 56b5fd1..bef70c0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,14 @@ ############################################################# GO +# For jane and tarzan +/janeserver/janeserver +/janeserver/ga10 + +/tarzan/tarzan +/tarzan/ta10 + + # Binaries for programs and plugins *.exe diff --git a/etc/standardintents/commonintents.sha256 b/__init__.py similarity index 100% rename from etc/standardintents/commonintents.sha256 rename to __init__.py diff --git a/docs/automaticStartup.md b/docs/automaticStartup.md index 64e1431..53c46c0 100644 --- a/docs/automaticStartup.md +++ b/docs/automaticStartup.md @@ -4,7 +4,7 @@ In this section we present an example distribution for use in a systemd environm ## Example File Layout (Linux/BSD) -One possible layout is to put everything in `/opt/jane`. Note, `janeserver` and `ta10` are put together just for convenience. Set permissions accordingly. +One possible layout is to put everything in `/opt/jane`. Note, `janeserver` and `tarzan` are put together just for convenience. Set permissions accordingly. ```bash $ pwd @@ -13,7 +13,7 @@ $ ls -l total 27364 -rw-rw-r-- 1 ian ian 706 tammi 21 13:01 config.yaml -rwxrwxr-x 1 ian ian 19448208 tammi 21 13:00 janeserver --rwxrwxr-x 1 ian ian 8554460 tammi 21 13:02 ta10 +-rwxrwxr-x 1 ian ian 8554460 tammi 21 13:02 tarzan -rw-rw-r-- 1 ian ian 1440 tammi 21 13:01 temporary.crt -rw-rw-r-- 1 ian ian 1704 tammi 21 13:01 temporary.key ``` @@ -44,19 +44,19 @@ Ensure the `config.yaml` is properly configured for your system and installation Start with `systemctl start jane.service` and enable with `systemctl enable jane.service`. Use `journalctl -xe` to check startup and possible errors. -## TA10 and +## Tarzan -This is how to start ta10. It works on BSDs, Linux, Windows and quite a few others depending upon the binary. Instructions here for starting with systemd and rc.3 which'll probably transfer between many Linux and BSD installations. Windows seems to work too +This is how to start tarzan. It works on BSDs, Linux, Windows and quite a few others depending upon the binary. Instructions here for starting with systemd and rc.3 which'll probably transfer between many Linux and BSD installations. Windows seems to work too -### Linxu with Systemd +### Linux with Systemd -Place the following systemd configuration in `/etc/systemd/system` as `ta10.service` +Place the following systemd configuration in `/etc/systemd/system` as `tarzan.service` -Note ta10 may require root to run. Take note of any security aspects. +Note tarzan may require root to run. Take note of any security aspects. Ensure that tarzan starts the correct services - these are all made on the command line, see [here](running.md)!! ``` [Unit] -Description=TA10 Trust Agent +Description=Tarzan Trust Agent After=network.target StartLimitIntervalSec=0 @@ -65,28 +65,28 @@ Type=simple Restart=always RestartSec=1 User=root -ExecStart=/opt/jane/ta10 +ExecStart=/opt/jane/tarzan --tpm2 --sys [Install] WantedBy=multi-user.target ``` -Start with `systemctl start ta10.service` and enable with `systemctl enable ta10.service`. Use `journalctl -xe` to check startup and possible errors. +Start with `systemctl start tarzan.service` and enable with `systemctl enable tarzan.service`. Use `journalctl -xe` to check startup and possible errors. ### Windows -This is possible. In the respository in `dist` is a file `ta10TrustAgent.xml` which provides some hints on this. +This is possible. In the respository in `dist` is a file `TarzanTrustAgent.xml` which provides some hints on this. ### BSD (rc.d) -Yes too. This script placed in `/etc/rc.d` called `ta10` works for startup, at least on my OpenBSD VM: +Yes too. This script placed in `/etc/rc.d` called `tarzan` works for startup, at least on my OpenBSD VM: ``` #!/bin/sh # -# $OpenBSD: ta10 +# $OpenBSD: tarzan -daemon="/opt/jane/ta10" +daemon="/opt/jane/tarzan" . /etc/rc.d/rc.subr diff --git a/docs/compiling.md b/docs/compiling.md index 8b6f992..ec794fd 100644 --- a/docs/compiling.md +++ b/docs/compiling.md @@ -9,7 +9,7 @@ The instructions presented here have been tested in Ubuntu 22.04 om AMD64. + [Install SGX SDK and Edgeless libraries](#install-sgx-sdk-and-edgeless-libraries) + [Building ](#building) + [Optional BUILD flag](#optional-build-flag) - * [Compiling TA10](#compiling-ta10) + * [Compiling tarzan](#compiling-tarzan) @@ -31,7 +31,8 @@ wget -q https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key -O / echo "deb [signed-by=/etc/apt/keyrings/intel-sgx-keyring.asc arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu jammy main" > /etc/apt/sources.list.d/intel-sgx.list apt update wget https://github.com/edgelesssys/edgelessrt/releases/download/v0.4.1/edgelessrt_0.4.1_amd64_ubuntu-22.04.deb -apt-get install -y ./$ERT_DEB build-essential cmake libssl-dev libsgx-dcap-default-qpl libsgx-dcap-ql libsgx-dcap-quote-verify +apt-get install -y build-essential cmake libssl-dev libsgx-dcap-default-qpl libsgx-dcap-ql libsgx-dcap-quote-verify +dpkg -i ./edgelessrt_0.4.1_amd64_ubuntu-22.04.deb ``` @@ -40,48 +41,46 @@ apt-get install -y ./$ERT_DEB build-essential cmake libssl-dev libsgx-dcap-defau Once SGX and Edgeless have been installed then you can just run this part every time you need to recompile. *MAKE SURE* you are in the `janeserver` directory when you run these commands: ```bash -go get -u -go mod tidy -. /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=linux GOARCH=amd64 go build -o janeserver +make build ``` -You will now get a file called `janeserver` which is your executable. - -If you wish to reduce the size of the binary, run `strip janeserver` +You will now get a file called `janeserver` which is your executable. The Makefile also sets BUILD and VERSION flags. Further the Makefile also genates a PIE binary for security reasons. -### Optional BUILD flag +### Optional BUILD and VERSION flags -If you wish to set a build flag, then specify as part of the `ldflags -X` option as in the example command to compile below. Set the value `123` to whatever you want (within reason - a short string is fine). If you don't do this, and it is completely optional, then default value for the build flag will be `not set`. +If you wish to set build and version flag, then specify as part of the `ldflags -X` option as in the example command to compile below. Set the value `123` to whatever you want (within reason - a short string is fine). If you don't do this, and it is completely optional, then default value for the build flag will be `not set`. ```bash -. /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=linux GOARCH=amd64 go build -ldflags="-X 'main.BUILD=123'" -o janeserver +. /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=linux GOARCH=amd64 go build -ldflags="-X 'main.BUILD=123 main.VERSION=0.9'" -o janeserver ``` - -## Compiling TA10 + +## Compiling tarzan +Tarzan is a reference trust agent implementation that responds to the A10HTTPREST protocol. Tarzan is only required if you want to use this protocol - it is useful for debugging and building interesting tests. -*MAKE SURE* you are in the `ta10` directory. TA10 is much simpler than janeserver and requires just compilation. For your local operating system and architecture you can remove the `GOOS` and `GOARCH` variables, for example as shown below. The `strip` command is optional but it does reduce the binary size a little. +*MAKE SURE* you are in the `tarzan` directory. tarzan is much simpler than janeserver and requires just compilation. ```bash -go get -u -go mod tidy -go build -o ta10 -strip ta10 +Make build ``` -For other architectures, use `go tool dist list` for a list of operating system and architecture options. Listed below are a few common options - and we like to append this to the binary name when we're generating a few of these for the devices we have (remeber amd64 is 64-bit Intel/AMD x86 based chips, eg: Xeons, i9's, i7's, Threaripper etc etc) +This generates a PIE binary with BUILD and VERSION tags set for amd64 linux. + +BUILD and VERSION flags are similar to janeserver. + +For other architectures you can build tarzan manually: use `go tool dist list` for a list of operating system and architecture options. Listed below are a few common options - and we like to append this to the binary name when we're generating a few of these for the devices we have (remeber amd64 is 64-bit Intel/AMD x86 based chips, eg: Xeons, i9's, i7's, Threaripper etc etc) ```bash -GOOS=linux GOARCH=arm go build -o ta10_arm # eg: Pi 3s -GOOS=linux GOARCH=arm64 go build -o ta10_arm64 # eg: Pi 4, 5s in 64-bit mode (also 3's I think) -GOOS=windows GOARCH=amd64 go build -o ta10_win # eg: Pretty much every Win10, Win11 machine -GOOS=plan9 GOARCH=386 go build -o ta10_belllabs # Because I was in Bell Labs and plan9 was freaking cool! The real Unix next! -GOOS=linux GOARCH=s390x go build -o ta10_mainframe # Because you either have an z-Series in the basement or Hercules -GOOS=solaris GOARCH=amd64 go build -o ta10_solaris # I still mourn the lost of the SparcStation and UltraSparcs, RIP Sun. -GOOS=opebsd GOARCH=amd64 go build -o ta10_openbsd # BSD for security (netbsd and freebsd are supported too) -GOOS=darmin GOARCH=arm64 go build -o ta10_mac # For the Apple people out there...no TPM, but if you figure out attesting a T2 let me know -GOOS=aix GOARCH=ppc64 go build -o ta10_aix # If you have an AIX box, again let me know...DRTM is supported during boot and a TPM too? -GOOS=wasip1 GOARCH=wasm go build -o ta10_aix # Web Assembly works too...never tried this myself, so I wonder how it works +GOOS=linux GOARCH=arm go build -o tarzan_arm # eg: Pi 3s +GOOS=linux GOARCH=arm64 go build -o tarzan_arm64 # eg: Pi 4, 5s in 64-bit mode (also 3's I think) +GOOS=windows GOARCH=amd64 go build -o tarzan_win # eg: Pretty much every Win10, Win11 machine +GOOS=plan9 GOARCH=386 go build -o tarzan_belllabs # Because I was in Bell Labs and plan9 was freaking cool! The real Unix next! +GOOS=linux GOARCH=s390x go build -o tarzan_mainframe # Because you either have an z-Series in the basement or Hercules +GOOS=solaris GOARCH=amd64 go build -o tarzan_solaris # I still mourn the lost of the SparcStation and UltraSparcs, RIP Sun. +GOOS=opebsd GOARCH=amd64 go build -o tarzan_openbsd # BSD for security (netbsd and freebsd are supported too) +GOOS=darmin GOARCH=arm64 go build -o tarzan_mac # For the Apple people out there...no TPM, but if you figure out attesting a T2 let me know +GOOS=aix GOARCH=ppc64 go build -o tarzan_aix # If you have an AIX box, again let me know...DRTM is supported during boot and a TPM too? +GOOS=wasip1 GOARCH=wasm go build -o tarzan_aix # Web Assembly works too...never tried this myself, so I wonder how it works ``` diff --git a/docs/contents.md b/docs/contents.md index 080aff9..7c91211 100644 --- a/docs/contents.md +++ b/docs/contents.md @@ -2,25 +2,22 @@ ## Basics -How do do things manually... +How to do things manually... * [Compiling](compiling.md) * [Running](running.md) * [Automatic Startup](automaticStartup.md) * [Security and Running in a Production Environment](security.md) -How do do things with Docker... +How to do things with Docker and other things... * [Building and Running with Docker](docker.md) + * [Building and Instasllating with DEB and RPM](deb.md) -## Getting Started +How do I get started? - * Creating an element - * Loading the standard intents - * Your first attestation - * Creating and expected value - * Verification - * More attestation and verification + * [Getting Started](gettingstarted.md) + * [UI, if on the local machine and default port](http://127.0.0.1:8540) ## Structures diff --git a/docs/deb.md b/docs/deb.md new file mode 100644 index 0000000..6c214de --- /dev/null +++ b/docs/deb.md @@ -0,0 +1,132 @@ +# Building and Installaing with DEB and RPM files + +First ensure you know how to build things manually...or not. + +## Generating the DEB and RPM files + +Change to the `etc\debbuild` director, then run the build script: + +```bash +./debbuild.sh +``` + +This will generate the gzipped deb and rpm files for jane and tarzan. It will compile both, build the deb, lint it and convert them to rpms. + +NB: linting will only work with `lintian` is installed, and the rpm generation only if `alien` is installed. Otherwise you'll get errors. At minimum you'll get gzipped deb files. + +The installer creates a directory in `/tmp` where the deb and rpm files will be found, eg: + +```bash +ian@Debian:/tmp/janedebbuild$ ls -l +total 20216 +drwxr-xr-x 5 ian ian 4096 Dec 2 19:40 jane +-rw-r--r-- 1 ian ian 5859658 Dec 2 19:41 janeattestationengine-1.0-2.x86_64.rpm.gz +-rw-r--r-- 1 ian ian 4420056 Dec 2 19:41 jane.deb.gz +drwxr-xr-x 5 ian ian 4096 Dec 2 19:40 tarzan +-rw-r--r-- 1 ian ian 4866350 Dec 2 19:41 tarzan.deb.gz +-rw-r--r-- 1 ian ian 5535737 Dec 2 19:41 tarzantrustagent-1.0-2.x86_64.rpm.gz +``` + + +## Installation with DEB + +As root run `dpkg -i ./jane.deb` and/or `dpkg -i ./tarzan.deb` + +In both cases the jane and tarzan services will the enabled with systemd. Tarzan will also run - check with journalctl. + +Example output is below: + +```bash +$ su - +Password: +root@Debian:~# cd /tmp/janedebbuild/ +root@Debian:/tmp/janedebbuild# gunzip jane.deb.gz +root@Debian:/tmp/janedebbuild# gunzip tarzan.deb.gz +root@Debian:/tmp/janedebbuild# dpkg -i ./jane.deb +Selecting previously unselected package janeattestationengine. +(Reading database ... 206615 files and directories currently installed.) +Preparing to unpack ./jane.deb ... +Unpacking janeattestationengine (1.0) ... +Setting up janeattestationengine (1.0) ... +Running post installation scripts +Enabling Jane with systemd +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + *** CHECK!!!!! **** +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + Edit the /opt/etc/jane/config.yaml + Regenerate keys in /opt/etc/jane +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Post installation scripts complete +root@Debian:/tmp/janedebbuild# dpkg -i ./tarzan.deb +Selecting previously unselected package tarzantrustagent. +(Reading database ... 206623 files and directories currently installed.) +Preparing to unpack ./tarzan.deb ... +Unpacking tarzantrustagent (1.0) ... +Setting up tarzantrustagent (1.0) ... +Running post installation scripts +Enabling Tarzan with systemd +Starting Tarzan with systemd +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + *** CHECK!!!!! **** +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + Edit the /etc/systemd/system/tarzan.service + Ensure Tarzan is runnign the correct services +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Post installation scripts complete +``` + +The results of checking the status with systemd are below. Note that jane *has not* been started - only enabled. + +```bash +root@Debian:/tmp/janedebbuild# systemctl status jane.service +○ jane.service - Jane Attestation Engine + Loaded: loaded (/etc/systemd/system/jane.service; enabled; preset: enabled) + Active: inactive (dead) +root@Debian:/tmp/janedebbuild# systemctl status tarzan.service +● tarzan.service - Tarzan Trust Agent + Loaded: loaded (/etc/systemd/system/tarzan.service; enabled; preset: enabled) + Active: active (running) since Mon 2024-12-02 20:26:30 EET; 1min 51s ago + Main PID: 7224 (tarzan) + Tasks: 6 (limit: 38436) + Memory: 3.3M + CPU: 2ms + CGroup: /system.slice/tarzan.service + └─7224 /opt/jane/tarzan --sys + +Dec 02 20:26:30 Debian tarzan[7224]: +======================================================== +Dec 02 20:26:30 Debian tarzan[7224]: | TA10 version - Starting +Dec 02 20:26:30 Debian tarzan[7224]: | + linux O/S on amd64 +Dec 02 20:26:30 Debian tarzan[7224]: | + version v0.2, build Mon Dec 2 07:40:59 PM EET 2024 main.VERSION=locally_compiled +Dec 02 20:26:30 Debian tarzan[7224]: | + session identifier is 7e050497-9570-45d8-9445-addfe8c6226c +Dec 02 20:26:30 Debian tarzan[7224]: | + unsafe mode? false +Dec 02 20:26:30 Debian tarzan[7224]: +======================================================== +Dec 02 20:26:30 Debian tarzan[7224]: +-- Sys attestation API enabled +Dec 02 20:26:30 Debian tarzan[7224]: +-- HTTP interface on port :8530 enabled +Dec 02 20:26:30 Debian tarzan[7224]: ⇨ http server started on [::]:8530 +``` + +## Removal with DEB + +Simply stop and disable the services, then purge. For example: + +```bash +root@Debian:/tmp/janedebbuild# systemctl stop jane.service +root@Debian:/tmp/janedebbuild# systemctl stop tarzan.service +root@Debian:/tmp/janedebbuild# systemctl disable jane.service +Removed "/etc/systemd/system/multi-user.target.wants/jane.service". +root@Debian:/tmp/janedebbuild# systemctl disable tarzan.service +Removed "/etc/systemd/system/multi-user.target.wants/tarzan.service". +root@Debian:/tmp/janedebbuild# dpkg -P janeattestationengine +(Reading database ... 206625 files and directories currently installed.) +Removing janeattestationengine (1.0) ... +Purging configuration files for janeattestationengine (1.0) ... +dpkg: warning: while removing janeattestationengine, directory '/etc/opt' not empty so not removed +root@Debian:/tmp/janedebbuild# dpkg -P tarzantrustagent +(Reading database ... 206618 files and directories currently installed.) +Removing tarzantrustagent (1.0) ... +Purging configuration files for tarzantrustagent (1.0) ... +``` + +## Installation and RPM with RPM + +Probably similar to DEB, you can figure this out. \ No newline at end of file diff --git a/docs/docker.md b/docs/docker.md index 2903d42..97e15bf 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -119,6 +119,6 @@ The following services are running and available externally by default -## TA10 +## TARZAN -Refer back to [compiling](compiling.md) to understand how to build TA10. This normally doesn't need to be run in a container (and we don't really recommend it anyway) \ No newline at end of file +Refer back to [compiling](compiling.md) to understand how to build tarzan. This normally doesn't need to be run in a container (and we don't really recommend it anyway) \ No newline at end of file diff --git a/docs/elements.md b/docs/elements.md index c3e013f..0737308 100644 --- a/docs/elements.md +++ b/docs/elements.md @@ -30,6 +30,8 @@ In following fields are part of the *hostmachine* entry | os | String | The operating system of the host machine | | arch | String | The CPU architecture of the host machine | | hostname | String | The hostname | +| machineid | String | A unique identifier of a machine, typicallys /etc/machine-id as found in Debian and Ubuntu distributions | + ### SSHKEY In following fields are part of the *sshkey* entry @@ -103,7 +105,7 @@ In following fields are part of the *mrmarbleinstance* entry ## Go Definition -The definition of the element structure can be found at https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/janeserver/structures/elements.go?ref_type=heads +The definition of the element structure can be found at https://github.com/iolivergithub/jane/blob/main/janeserver/structures/elements.go ## Example @@ -122,6 +124,6 @@ The definition of the element structure can be found at https://gitlab.jyu.fi/ij "public" : "a104e0972158670651d901de333cb05990443e8088daa1cd1b52c274c23c83d637bbb95427da10c5ebe62a96da4570486d1bdd38563942f6fca15cd2890aed9018d0becc5231fe5139a18cd8d21e3844ec339da07729fa2615ad1ed542a3167a3696c4173e710a0346bf3d457034ce8cd861a21578fe07d407aee421275e06aed3840004042f99899392ac6ea17314c52839cd92ee37773a8bb6b3dc4d42e032c224a965561d555cd2b3f7ccfc7504eb2ba67dabd094e0c7633d7d9bdcab26f03859efaa0451e38213f2d173fdb8c8e03b24e934b74c5c114e64207fcea104e0972158670651d901de333cb05990443e8088daa1cd1b52c274c23c83d637bbb95427da10c5ebe62a96da4570486d1bdd38563942f6fca15cd2890aed9018d0becc5231fe5139a18cd8d21e3844ec339da07729fa2615ad1ed542a3167a3696c4173e710a0346bf3d457034ce8cd861a21578fe07d407aee421275e06aed3840004042f99899392ac6ea17314c52839cd92ee37773a8bb6b3dc4d42e032c224a965561d555cd2b3f7ccfc7504eb2ba67dabd094e0c7633d7d9bdcab26f03859efaa0451e38213f2d173fdb8c8e03b24e934b74c5c114e64207fce952082a32534a8900083150a617fa1bd4793a33d83aa3668983e8001f852aa353c12cb", "name" : "000bbaff812d583ae10504643d252fb051ac9b6203d4d59be83d8514c9f55a93f61d" } }, - "host" : { "os" : "linux", "arch" : "arm", "hostname" : "testsys" } + "host" : { "os" : "linux", "arch" : "arm", "hostname" : "testsys", "machineid":"39086971-960e-422a-a636-cb8bc7f1ad72"} } ``` \ No newline at end of file diff --git a/docs/expectedvalues.md b/docs/expectedvalues.md index f42206d..3f3a8d7 100644 --- a/docs/expectedvalues.md +++ b/docs/expectedvalues.md @@ -23,14 +23,14 @@ This is a dictionary of values utilised by various rules - the specific names an | Field Name | Description | | --- | --- | -| attestedValue | Value for the TPM 2.0 Quote attested value field | -| firmwareVersion | TPM 2.0 firmware version number | +| attestedValue | Value for the TPM 2.0 Quote attested value field, used with pcrQuotes | +| firmwareVersion | TPM 2.0 firmware version number, used with pcrQuotes | Refer to the code linked in the next section and rule definitions for more field details ## Go Definition -The definition of the element structure can be found at https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/janeserver/structures/expectedValues.go +The definition of the expected value structure can be found at https://github.com/iolivergithub/jane/blob/main/janeserver/structures/expectedValues.go ## Example diff --git a/docs/gettingstarted.md b/docs/gettingstarted.md new file mode 100644 index 0000000..391a96e --- /dev/null +++ b/docs/gettingstarted.md @@ -0,0 +1,31 @@ +# Getting Started + +In the following sections we explain how to get started with Jane and explore some of its features. We assume that you have Jane up and [running](running.md) and that you can get to the web UI. + + * Overview of the UI + * Creating an element + * Loading the standard intents + * Your first attestation + * Creating and expected value + * Verification + * More attestation and verification + +# Overview of the UI + +Point your browser at the UI, eg: (http://127.0.0.1:8540) if you are running on a local machine on the default port. You should see something like this: + +![Jane WebUI Home Page](images/janewebuihomepage.png "Jane WebUI Home Page") + +This shows the overall status of the system. The upper part showing the contents of the database and the lower part the congfiguration of the system. In our example we can see that we have 1 element, 12 intents, 2 expected values etc. Clicking on the titles of these will take you to a page which shows these items in more detail. + +The lower half shows the configuration: how janeserver was started and with what paratmers, what services are running and on what ports, the state of the MQTT messagebus, Mongo databaes and the logging file. + +The top bar is available on all pages and clicking on the home icon on the left-hand side will always bring you back to this page. + +## Help and About + +If you need help or wish for more history of Jane, then use the Help menu which has these Help... and About... options + +# Creating an Element + +The element is the core description of the thing to be attested. Typically this might be a physical machine, virtual machine, container, IoT device etc \ No newline at end of file diff --git a/docs/images/janewebuihomepage.png b/docs/images/janewebuihomepage.png new file mode 100644 index 0000000..4c3626c Binary files /dev/null and b/docs/images/janewebuihomepage.png differ diff --git a/docs/intents.md b/docs/intents.md index 8e419ac..3c5d3ba 100644 --- a/docs/intents.md +++ b/docs/intents.md @@ -24,7 +24,7 @@ The functions are provided by the protocols, a list of specific protocols and fu | Function | Description | Paramter Fields | | --- | --- | --- | -| tom2/pcrs | Requests the list of PCRs from a TPM 2.0 device | tpm2/device | +| tpm2/pcrs | Requests the list of PCRs from a TPM 2.0 device | tpm2/device | | tpm2/quote | Requets a quote from a TPM 2.0 | tpm2/device, pcrSelection, bank | | uefi/eventlog | | uefi/eventlog | | ima/asciilog | | ima/ASCIIlog| @@ -39,20 +39,20 @@ Specifics about intent functions are described here (functions.md)[functions]) ## Go Definition -The definition of the element structure can be found at https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/janeserver/structures/intents.go +The definition of the intent structure can be found at https://github.com/iolivergithub/jane/blob/main/janeserver/structures/intents.go ## Standard Intents -The file https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/etc/standardintents.json contains a standard list of common intents that can be loaded into Jane. These intents use a fixed `itemid` field so should be consistent across all installations. Further discussion of these is made here [Standard Intents](standardintents.md). +The file https://github.com/iolivergithub/jane/blob/main/etc/standardintents/standardintents.json contains a standard list of common intents that can be loaded into Jane. These intents use a fixed `itemid` field so should be consistent across all installations. Further discussion of these is made here [Standard Intents](standardintents.md). Jane contains a function in the UI to reload these on demand, hence the use of the standard itemid. The file is loaded from the above source. -The file https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/etc/standardintents.sha256 contains the hash of the standard intents. The value in this file should be `e02bb3a7f75e9fd4bdc826a089d23f6d1aaadda38640a409256d0c1459231582` +The file https://github.com/iolivergithub/jane/blob/main/etc/standardintents/standardintents.sha256 contains the hash of the standard intents. The value in this file should be `e02bb3a7f75e9fd4bdc826a089d23f6d1aaadda38640a409256d0c1459231582` This file might be loaded into mongodb like so, replace `DB` with the name of the attestation database in use (see: https://www.mongodb.com/docs/database-tools/installation/installation-linux/) ```bash -mongoimport --db DB --collection intents --file standarditents.json +mongoimport --db DB --collection intents --file standardintents.json ``` ## Example diff --git a/docs/running.md b/docs/running.md index c5c738f..73ce898 100644 --- a/docs/running.md +++ b/docs/running.md @@ -1,3 +1,12 @@ +# Table of contents + +- [Running JANESERVER](#running-janeserver) + - [JANESERVER Configuration File](#janeserver-configuration-file) + - [Using Keylime for Measured Boot evaluation](#using-keylime-for-measured-boot-evaluation) +- [Running TARZAN](#running-tarzan) + - [Command line options](#command-line-options) + - [Unsafe operation - Here be a good way to open your system to every hacker ever](#unsafe-operation---here-be-a-good-way-to-open-your-system-to-every-hacker-ever) + # Running JANESERVER Janeserver requires a configuration file and optionally keys for the https certs. We've supplied a temporary key in the dist folder...don't use these unless you're crazy. We also like triggering github to give us private key warnings because we've stored them there. Browsers will complain unless your certs a signed by a suitable authority, eg: LetsTrust. @@ -50,38 +59,7 @@ X3270 service listening on port 3270 If that works, point your browser at the machine where this is running and port 8540. - -# Running TA10 - -Running TA10 is simple, just use - -```bash -./ta10 -``` - -```bash -+======================================================================================== -| TA10 version - Starting -| + linux O/S on amd64 -| + version v0.1, build not set -| + session identifier is 19a14951-76c3-4641-b9ac-fa65683e5c36 -| + unsafe mode? false -+======================================================================================== - -⇨ http server started on [::]:8530 -``` - -If you are running on Linux and need access to files such as the UEFI log file then you will need to run ta10 as sudo. - -TA10 requires access to the TPM device, eg `/dev/tpm0` on Linux (Windows handles this internally), and so whichever user ta10 is running as needs access to that device. - -```bash -sudo ./ta10 -``` - -Read the section on advanced TA10 usage. - -# JANESERVER Configuration File +## JANESERVER Configuration File Note the lines with "CHANGE ME" - review these for your system. @@ -162,22 +140,74 @@ keylime: apiurl: https://127.0.0.1:30000/keylime #CHANGE ME ``` -# Advanced TA10 - Here be a good way to open your system to every hacker ever -TA10 CURRENTLY starts all the services, ie: it will happily offer TPM, IMA, UEFI services etc, even if these are not available. In a later version these will have be switched on specifically, but don't worry about this. -TA10 can read UEFI and IMA logs in non-standard places, but in order to do this, the element description in the Jane's database would have to refer to those specifically. TA10 by default operates in a *safe* mode where it will only use the standard locations in Linux's securityfs. You can turn off this mode: + + +# Running TARZAN + +Tarzan is a reference trust agent implementation that responds to the A10HTTPREST protocol. Running tarzan is simple, just speicfy which services you want started, eg: sys and tpm2... + +```bash +./tarzan --tpm2 --sys +``` + +```bash ++======================================================================================== +| tarzan version - Starting +| + linux O/S on amd64 +| + version v0.1, build not set +| + session identifier is 19a14951-76c3-4641-b9ac-fa65683e5c36 +| + unsafe mode? false ++======================================================================================== + +⇨ http server started on [::]:8530 +``` + +If you are running on Linux and need access to files such as the UEFI log file then you will need to run tarzan as sudo. + +tarzan requires access to the TPM device, eg `/dev/tpm0` on Linux (Windows handles this internally), and so whichever user tarzan is running as needs access to that device. + +```bash +sudo ./tarzan --tpm2 --sys +``` + + +## Command line options + +Tarzan's services and configuration is all done by command line flags. At least one of these must be specified for tarzan to respond to anything at all. At minimum the sys service just to report what system you are running on should be enabled. + +| Flag | Description | +| --- | --- | --- | +| --tpm2 | Start the services to respond to TPM2 attestation requests | +| --uefi | Start the services to respond to UEFI attestation requests | +| --ima | Start the services to respond to Linux IMA attestation requests | +| --txt | Start the services to respond to Intel TXT attestation requests | +| --sys | Start the services to respond to TPM2 attestation requests | + + +tarzan by default listens on port 8530, this can be changed using the --port option + +For example, to start tarzan on port 4789 and reporting on uefi, ima and sys you would use (possibly with sudo): + +```bash +tarzan --sysy --uefi --ima --port=4789 +``` + +## Unsafe operation - Here be a good way to open your system to every hacker ever + +tarzan can read UEFI and IMA logs in non-standard places, but in order to do this, the element description in the Jane's database would have to refer to those specifically. tarzan by default operates in a *safe* mode where it will only use the standard locations in Linux's securityfs. You can turn off this mode: ```bash -sudo ./ta10 -unsafe=true +sudo ./tarzan -unsafe=true ``` which responds with ```bash -$ sudo ./ta10 -unsafe=true +$ sudo ./tarzan -unsafe=true +======================================================================================== -| TA10 version - Starting +| tarzan version - Starting | + linux O/S on amd64 | + version v0.1, build not set | + session identifier is 4e85a08d-7d1c-450d-9a7a-659f29ab8380 @@ -186,7 +216,7 @@ $ sudo ./ta10 -unsafe=true !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -TA10 is running in UNSAFE file access mode. Unsafe is set to true +tarzan is running in UNSAFE file access mode. Unsafe is set to true Requests for log files, eg: UEFI, IMA, that supply a non default location will happily read that file This is a HUGE security issue. YOU HAVE BEEN WARNED !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/docs/security.md b/docs/security.md index e1f1931..dfd1658 100644 --- a/docs/security.md +++ b/docs/security.md @@ -8,8 +8,8 @@ Read carefully: * TO SAVE YOURSELF, SET THE use http FIELDS TO true in the configuration file. * That isn't secure either... * GENERATE YOUR OWN KEYS AND KEEP THEM SECURE and use https - * TA10 runs over HTTP !!!! - * DO NOT USE TA10 IN UNSAFE MODE !!! (Even if you're not root!) + * Tarzan runs over HTTP !!!! + * DO NOT USE Tarzan IN UNSAFE MODE !!! (Even if you're not root!) * Jane signs claims, results, sessions etc...the keys are randomly generated each him the system is started and aren't recorded anywhere. There is some code to talk PKCS#11 and has been tested with a YubiHSM but it isn't used. Don't rely upon it, I haven't tested it and it is just placeholder at this time. Yes, I'll get arund to writing the proper functionality real soon now...volunteers? * Did I tell you that the temporary.key and temporary.crt have been on github and gitlab pages for years; also in the forks and elsewhere...? diff --git a/docs/standardintents.md b/docs/standardintents.md index cefbc45..348c5c7 100644 --- a/docs/standardintents.md +++ b/docs/standardintents.md @@ -1,6 +1,6 @@ # Standard Intents -The standard intents are a set of intents which are common across all installations and express typical scenarios. The file https://gitlab.jyu.fi/ijoliver/jane/-/blob/main/etc/standardintents.json contains a standard list of common intents and instructions on loading these are on [intents](intents.md) page. +The standard intents are a set of intents which are common across all installations and express typical scenarios. The file https://github.com/iolivergithub/jane/etc/standardintents/standardintents.json contains a standard list of common intents and instructions on loading these are on [intents](intents.md) page. ## List of Standard Intents diff --git a/etc/debbuild/REPLACE_ME.crt b/etc/debbuild/REPLACE_ME.crt new file mode 100644 index 0000000..0d28303 --- /dev/null +++ b/etc/debbuild/REPLACE_ME.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEBTCCAu2gAwIBAgIUDrqpf0GSBBBR4je23TbLOyrYK0YwDQYJKoZIhvcNAQEL +BQAwgZExCzAJBgNVBAYTAkZJMRgwFgYDVQQIDA9KeXbDg8Kkc2t5bMODwqQxGDAW +BgNVBAcMD0p5dsODwqRza3lsw4PCpDEMMAoGA1UECgwDSllVMRwwGgYDVQQDDBNE +TyBOT1QgVVNFIFRISVMgS0VZMSIwIAYJKoZIhvcNAQkBFhNETyBOT1QgVVNFIFRI +SVMgS0VZMB4XDTI0MDYyMDIwMTYwMFoXDTI1MDYyMDIwMTYwMFowgZExCzAJBgNV +BAYTAkZJMRgwFgYDVQQIDA9KeXbDg8Kkc2t5bMODwqQxGDAWBgNVBAcMD0p5dsOD +wqRza3lsw4PCpDEMMAoGA1UECgwDSllVMRwwGgYDVQQDDBNETyBOT1QgVVNFIFRI +SVMgS0VZMSIwIAYJKoZIhvcNAQkBFhNETyBOT1QgVVNFIFRISVMgS0VZMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvYuEZ0h5N0ROk8eJ8z+15WdhDULn +W1byC7nMa75umjNW0BtFCl4t+HzswWphd5kkeNygg+go+9XTrPBn6e8YFOUigutT +2KVd88LzYCPrKQgwBEWuC+4JhWCnIYy0b1FdU8CZQfo9I6aC16/FE5oV73MrIKGN +QEOWE7nLa9iemqC329YpE55l/x1lH/OYdc8U43/IOKcTtJTcZp11uCVwOlyNS7c3 +gZ+gF+p/vhazMVYmXbK2BbC7nr+WDltxFUYwFaKBy0Z/alHCeF7u4dPwwVoeKBLO +8ut94sMHun02KPI/d+O65G6PVG5nkEkWvAv/+SS/ycmZbJHYHpLOaLZH6wIDAQAB +o1MwUTAdBgNVHQ4EFgQUC9duecgzQ/fg4RFGxjc5XZV9SZgwHwYDVR0jBBgwFoAU +C9duecgzQ/fg4RFGxjc5XZV9SZgwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQsFAAOCAQEAapO4UkEkbfceCaHFKgcKPw+QSSKMTqyVtA4J+447gRRYTvl+JmZD +bY2x+U2XRCsK8SCjHJgkb41mrqzlOYGufITJbn32KmaMANDrlXZpnacEmCPONM34 +Ys/gBUaCamxxcJpmEz0j72q/ejgtveUIktKuIUoJ336DThgesc1ioPwMfWAb9SE1 +ZLwz9L+UCYDNj5WeOhGt5eFMNUVO7unkC9R+aMuQ/F1X8YnkYgRdKS2VMXFVdUv2 +BTkPIokCrgLPRpUToqfpf3vUOL8PQSQmUH3zsrDHqApL0cPTxN2uXjkgHz5nFLqI +lj7dH10bHN3faEc3SQ02hZka4F5RxHXURw== +-----END CERTIFICATE----- diff --git a/etc/debbuild/REPLACE_ME.key b/etc/debbuild/REPLACE_ME.key new file mode 100644 index 0000000..a581f28 --- /dev/null +++ b/etc/debbuild/REPLACE_ME.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9i4RnSHk3RE6T +x4nzP7XlZ2ENQudbVvILucxrvm6aM1bQG0UKXi34fOzBamF3mSR43KCD6Cj71dOs +8Gfp7xgU5SKC61PYpV3zwvNgI+spCDAERa4L7gmFYKchjLRvUV1TwJlB+j0jpoLX +r8UTmhXvcysgoY1AQ5YTuctr2J6aoLfb1ikTnmX/HWUf85h1zxTjf8g4pxO0lNxm +nXW4JXA6XI1LtzeBn6AX6n++FrMxViZdsrYFsLuev5YOW3EVRjAVooHLRn9qUcJ4 +Xu7h0/DBWh4oEs7y633iwwe6fTYo8j9347rkbo9UbmeQSRa8C//5JL/JyZlskdge +ks5otkfrAgMBAAECggEAXIeUTjtB+WneFiRNwrKyYFfUN/4WJS/Pn0vHcD2ZjqtL +UPJPBN2vAWQyy8Tb6d+Xv2ys61fVUgMzf3Qotjmi/uhQraql1tf7gnkECEXgkbpO +fndpnKdKfJMPY8BlgQYuUiluZ5f6asHpk9NZmNUaqjcFsbtL0jhsNhr4JCCuZHsB +rgYxc1bB1lKvixYk0wckJL6hD8Rpyloywyh+AvereoXqM1kbORCA2rY7yOehzwCr +i97C1LKu+i+8G7Dag8sZO4SfYbATh1BlFoZcWVS3yTh7FLN64mHA5fwmZwgpGWXm +hcK9bM2RtM494ViZ9tS8C7tpImuPyIyahecUIgRsgQKBgQD9s3Ihngcv70FFOBdR +4KhfvdLFdS/3pDDLhYrbGEP1jYbigzlGYtqAQTzSXj7k+/5Q899n9435Eib1ubny +1+lcRtgCnX+4iLWN9K+nTlaq1Se408TW9JUKCEZsLhEhqPM8iq35Z0YGduShbvAw +UVF+Pg1hRJmO9r2w7REKoYewKwKBgQC/QzzVMCZaY6Zm5iiY3P2+ykomlY4wscUw +tRGqm70JIPX9B/OOFtOTgI4M4+JxLtV2+O8rXSxG0bWpi5I3VL0i4Eq/6RX14WUN +yVw/FrevWqzFrUuo119AkoTELAVFxTH9wI7guTABEpswMl8Cy7ArY2Fk/K4jiXAb +THnZykQnQQKBgQD1m0GElg5zM3bG4jSBSbL3bTedfYPAhK3QeiohTW6NTEQnCc7q ++0x5Ga8eIatV1zcve8juR9SkKhSZkwIXvTrn4JXCgmNhbMgG87kRiV+R5uWbozhO +uV2H5tb2Z+qh4YQJOmCOsJI0M+nG9zWEMVVpl/0wC091/h1KKVd0KUjJHQKBgQCG +mKKuxHu5EHeB4mafbKWFJoaYMJcn3XKPnF0aWw7k5bU2o+naDGZIXyeYGqa4T+UZ +HIXzVlZaYCofboEvPwr7CCyScU1rA3tCAHpSS4JofL8pPZMI9sepgXK9Ot1bBDLy +CBiEPM5zcsyTVl9WcFFBt2ZK0ycZCxdBnsgBZD4iAQKBgHifA8n0tV+stgD/bm15 +H7zIetYYZ+Uo5dOCV1RPTrrTByDRbAEXRn2YlxhU8mlPRnKS+UVMiTRtpJFTGywl +rbq8zwqGlAtHy4U0d7WI3a/Gx61ifCvCKbK4arTBERR45Jn41d3l/tdgdArFXorj +NaViz3ie0LYIWFF1feS4Q3Kq +-----END PRIVATE KEY----- diff --git a/etc/debbuild/conffiles_jane b/etc/debbuild/conffiles_jane new file mode 100644 index 0000000..671b51e --- /dev/null +++ b/etc/debbuild/conffiles_jane @@ -0,0 +1,4 @@ +/etc/opt/jane/config.yaml +/etc/opt/jane/REPLACE_ME.key +/etc/opt/jane/REPLACE_ME.crt +/etc/systemd/system/jane.service diff --git a/etc/debbuild/conffiles_rima b/etc/debbuild/conffiles_rima new file mode 100644 index 0000000..179a85f --- /dev/null +++ b/etc/debbuild/conffiles_rima @@ -0,0 +1,2 @@ +/etc/systemd/system/rima.service +/opt/jane/rima.db diff --git a/etc/debbuild/conffiles_tarzan b/etc/debbuild/conffiles_tarzan new file mode 100644 index 0000000..153befc --- /dev/null +++ b/etc/debbuild/conffiles_tarzan @@ -0,0 +1 @@ +/etc/systemd/system/tarzan.service diff --git a/etc/debbuild/config.yaml b/etc/debbuild/config.yaml new file mode 100644 index 0000000..7335d26 --- /dev/null +++ b/etc/debbuild/config.yaml @@ -0,0 +1,43 @@ +#Some general naming +system: + name: ASVR_GO_1_DEBBUILD + + +#MongoDB Configuration +database: + connection: mongodb://127.0.0.1:27017 + name: asvr + + +#MQTT Configuration +messaging: + broker: 127.0.0.1 + port: 1883 + clientid: asvrgo1debbuild + + +#REST Interface Configuration +rest: + port: 8520 + crt: /etc/opt/jane/REPLACE_ME.crt + key: /etc/opt/jane/REPLACE_ME.key + usehttp: true + + +#Web Interface Configuration +web: + port: 8540 + crt: /etc/opt/jane/REPLACE_ME.crt + key: /etc/opt/jane/REPLACE_ME.key + usehttp: true + + +#Web Interface Configuration +x3270: + port: 3270 + + +#Log file +logging: + logfilelocation: /var/log/jane/jane.log + sessionupdatelogging: false diff --git a/etc/debbuild/control_jane b/etc/debbuild/control_jane new file mode 100644 index 0000000..c86c6cc --- /dev/null +++ b/etc/debbuild/control_jane @@ -0,0 +1,8 @@ +Package: janeattestationengine +Version: 1.0 +Maintainer: Ian Oliver +Architecture: amd64 +Priority: optional +Section: admin +Description: Jane Attestation Engine: + Test DEB packaging diff --git a/etc/debbuild/control_rima b/etc/debbuild/control_rima new file mode 100644 index 0000000..3b0c934 --- /dev/null +++ b/etc/debbuild/control_rima @@ -0,0 +1,8 @@ +Package: rimapolicyengineforjane +Version: 1.0 +Maintainer: Ian Oliver +Architecture: amd64 +Priority: optional +Section: admin +Description: Rima Policy Engine for Jane: + Test DEB packaging diff --git a/etc/debbuild/control_tantor b/etc/debbuild/control_tantor new file mode 100644 index 0000000..0624e0c --- /dev/null +++ b/etc/debbuild/control_tantor @@ -0,0 +1,8 @@ +Package: tantorattestationprovisioner +Version: 1.0 +Maintainer: Ian Oliver +Architecture: amd64 +Priority: optional +Section: admin +Description: Tantor Attestation Engine Device Provisioner: + Test DEB packaging diff --git a/etc/debbuild/control_tarzan b/etc/debbuild/control_tarzan new file mode 100644 index 0000000..d69cb00 --- /dev/null +++ b/etc/debbuild/control_tarzan @@ -0,0 +1,9 @@ +Package: tarzantrustagent +Version: 1.0 +Maintainer: Ian Oliver +Architecture: amd64 +Priority: optional +Section: admin +Description: Tarzan Trust Agent for Jane: + Test DEB packaging + diff --git a/etc/debbuild/debbuild.sh b/etc/debbuild/debbuild.sh new file mode 100755 index 0000000..450e167 --- /dev/null +++ b/etc/debbuild/debbuild.sh @@ -0,0 +1,140 @@ +#!/bin/sh + +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' + +DEBBUILDDIR=`pwd` +TMPBASE=/tmp/janedebbuild +JANEBASE=$TMPBASE/jane +TARZANBASE=$TMPBASE/tarzan +PROVBASE=$TMPBASE/provisioner + +echo "${GREEN}This file must be run in the ./jane/etc/debbuild directory${NC}" +echo "${GREEN} -- you are currently here:${RED} ${DEBBUILDDIR} ${NC}" + + +#first remove any temporary build directories +echo "${BLUE}Removing previous builds${NC}" +rm -rf ${TMPBASE}/* + + +#create the jane build directories +echo "${BLUE}Creating temporary build directories${NC}" +mkdir -p $JANEBASE +mkdir -p $JANEBASE/DEBIAN +mkdir -p $JANEBASE/opt/jane +mkdir -p $JANEBASE/var/log/jane +mkdir -p $JANEBASE/etc/opt/jane +mkdir -p $JANEBASE/etc/systemd/system + +mkdir -p $TARZANBASE +mkdir -p $TARZANBASE/DEBIAN +mkdir -p $TARZANBASE/opt/jane +mkdir -p $TARZANBASE/etc/systemd/system + + + +#compile Jane +echo "${BLUE}Compiling Janeserver${NC}" +cd ../../janeserver +make build +ls -l janeserver + +#compile Tarzan +echo "${BLUE}Compling Tarzan${NC}" +cd ../tarzan +make build +ls -l tarzan + + +#return to this directory +echo "${BLUE}Returning to build script directory ${RED}${DEBBUILDDIR}${NC}" +cd $DEBBUILDDIR + + +#Copy binaries +echo "${BLUE}Copying binaries" +cp ../../janeserver/janeserver $JANEBASE/opt/jane +cp ../../tarzan/tarzan $TARZANBASE/opt/jane + + +#Copy configuration files +echo "${BLUE}Copying congfiguration files and temporary keys" +cp config.yaml $JANEBASE/etc/opt/jane/config.yaml + +cp REPLACE_ME.key $JANEBASE/etc/opt/jane/REPLACE_ME.key +cp REPLACE_ME.crt $JANEBASE/etc/opt/jane/REPLACE_ME.crt + +cp jane.service $JANEBASE/etc/systemd/system/jane.service +cp tarzan.service $TARZANBASE/etc/systemd/system/tarzan.service + + + +#Copy control files +echo "${BLUE}Copying Debian control, conffile and postinst files${NC}" +cp control_jane $JANEBASE/DEBIAN/control +cp control_tarzan $TARZANBASE/DEBIAN/control +cp control_rima $RIMABASE/DEBIAN/control + +cp postinst_jane $JANEBASE/DEBIAN/postinst +cp postinst_tarzan $TARZANBASE/DEBIAN/postinst +cp postinst_rima $RIMABASE/DEBIAN/postinst + + + +#Build deb packages +echo "${BLUE}Building Debian package for Jane${NC}" +pwd +ls -l +cd $TMPBASE +dpkg-deb --root-owner-group --build jane + +echo "${BLUE}Building Debian package for Tarzan${NC}" +cd $TMPBASE +dpkg-deb --root-owner-group --build tarzan + + + + + +echo "${BLUE}Build complete, here are the deb files${NC}" + +ls -l jane.deb +ls -l tarzan.deb + +echo "${BLUE}Attempting to build rpms${NC}" +cd $TMPBASE + +alien -r -c -v jane.deb +alien -r -c -v tarzan.deb + +ls -l *.rpm + +#Linting deb packages +echo "${BLUE}Linting jane.deb${NC}" +cd $TMPBASE +lintian jane.deb + +echo "${BLUE}Linting tarzan.deb${NC}" +cd $TMPBASE +lintian tarzan.deb + + + + + +gzip *.deb +gzip *.rpm + + + +echo "${BLUE}Listing files${NC}" + +cd $TMPBASE +ls -l *.gz +ls -l *.pyz + +#Completion +echo "${BLUE}Complete${NC}" diff --git a/etc/debbuild/jane.service b/etc/debbuild/jane.service new file mode 100644 index 0000000..b08d828 --- /dev/null +++ b/etc/debbuild/jane.service @@ -0,0 +1,14 @@ +[Unit] +Description=Jane Attestation Engine +After=network.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=always +RestartSec=1 +User=ian +ExecStart=/opt/jane/janeserver --config=/etc/opt/jane/config.yaml + +[Install] +WantedBy=multi-user.target diff --git a/etc/debbuild/postinst_jane b/etc/debbuild/postinst_jane new file mode 100755 index 0000000..989e1b0 --- /dev/null +++ b/etc/debbuild/postinst_jane @@ -0,0 +1,27 @@ +#!/bin/sh + +RED='\033[0;31m' +YELLOW='\033[0;33m' +PURPLE='\033[0;35m' +NC='\033[0m' + +echo "${PURPLE}Running post installation scripts${NC}" + +echo "${PURPLE}Enabling Jane with systemd${NC}" +systemctl enable jane.service + +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} *** CHECK!!!!! **** ${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} Edit the /etc/opt/jane/config.yaml ${NC}" +echo "${RED} Replace keys in /etc/opt/jane${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} NOTE: janeserver HAS NOT been started${NC}" +echo "${RED} use: ${YELLOW}systemctl start jane.service${RED} once the${NC}" +echo "${RED} above configiguration files hecked and ${NC}" +echo "${RED} keys been replaced${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" + +echo "${PURPLE}Post installation scripts complete${NC}" + + diff --git a/etc/debbuild/postinst_rima b/etc/debbuild/postinst_rima new file mode 100755 index 0000000..0166fba --- /dev/null +++ b/etc/debbuild/postinst_rima @@ -0,0 +1,26 @@ +#!/bin/sh + +PURPLE='\033[0;35m' +NC='\033[0m' + +echo "${PURPLE}Running post installation scripts${NC}" + +echo "${PURPLE}Enabling Rima with systemd${NC}" +systemctl enable rima.service + +echo "${PURPLE}Starting Rima with systemd${NC}" +systemctl start rima.service + +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} *** CHECK!!!!! **** ${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} Edit the /etc/systemd/system/rima.service ${NC}" +echo "${RED} Ensure Rima has the correct parameters (see below)${NC}" +echo "${RED} NOTE #1: ${NC}" +echo "${RED} It is possible that Rima will not have started correctly${NC}" +echo "${RED} if it is configured incorrecly, eg: no Jane, no scripts, scripts not found etc${NC}" +echo "${RED} NOTE #2: ${NC}" +echo "${RED} Ensure that rima.db is correclt populated. A new install will write a test database${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" + +echo "${PURPLE}Post installation scripts complete${NC}" diff --git a/etc/debbuild/postinst_tarzan b/etc/debbuild/postinst_tarzan new file mode 100755 index 0000000..9e04a64 --- /dev/null +++ b/etc/debbuild/postinst_tarzan @@ -0,0 +1,21 @@ +#!/bin/sh + +PURPLE='\033[0;35m' +NC='\033[0m' + +echo "${PURPLE}Running post installation scripts${NC}" + +echo "${PURPLE}Enabling Tarzan with systemd${NC}" +systemctl enable tarzan.service + +echo "${PURPLE}Starting Tarzan with systemd${NC}" +systemctl start tarzan.service + +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} *** CHECK!!!!! **** ${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" +echo "${RED} Edit the /etc/systemd/system/tarzan.service ${NC}" +echo "${RED} Ensure Tarzan is running the correct services${NC}" +echo "${RED}!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!${NC}" + +echo "${PURPLE}Post installation scripts complete${NC}" diff --git a/etc/debbuild/provbuild.sh b/etc/debbuild/provbuild.sh new file mode 100755 index 0000000..2c189b5 --- /dev/null +++ b/etc/debbuild/provbuild.sh @@ -0,0 +1,24 @@ +#!/bin/sh +x + +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +NC='\033[0m' + +DEBBUILDDIR=`pwd` +TMPBASE=/tmp/janedebbuild +PROVBASE=$TMPBASE/provisioner + +echo "${BLUE}Building the provisioner python distributables${NC}" + +cd $DEBBUILDDIR/../.. +mkdir -p $PROVBASE +cp -R * $PROVBASE +cd $PROVBASE/.. +python3 -m venv provisioner +chmod a+x provisioner/bin/* +./provisioner/bin/activate +python3 -m pip3 install -r provisioner/requirements.txt --target provisioner +python3 -m zipapp -c -p "/usr/bin/python3" -o $TMPBASE/provisioner.pyz provisioner +deactivate +ls -l $TMPBASE/provisioner.pyz diff --git a/etc/debbuild/rima.db b/etc/debbuild/rima.db new file mode 100644 index 0000000..ee8a08a --- /dev/null +++ b/etc/debbuild/rima.db @@ -0,0 +1,2 @@ +ITEMID,ENDPOINT,POLNAME,SCRIPTNAME +d1b09fae-c996-4b4c-9678-0724cf15fc8c,a01rest,quick,script1.sh diff --git a/etc/debbuild/rima.service b/etc/debbuild/rima.service new file mode 100644 index 0000000..5062ce8 --- /dev/null +++ b/etc/debbuild/rima.service @@ -0,0 +1,14 @@ +[Unit] +Description=Rima Policy Engine for Jane +After=network.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=always +RestartSec=1 +User=ian +ExecStart=/opt/jane/rima -jane=https://127.0.0.1:8520 -port=8522 -db=/opt/jane/rima.db -scripts=/opt/jane/rimascripts -listen=0.0.0.0 + +[Install] +WantedBy=multi-user.target diff --git a/etc/debbuild/tarzan.service b/etc/debbuild/tarzan.service new file mode 100644 index 0000000..1398135 --- /dev/null +++ b/etc/debbuild/tarzan.service @@ -0,0 +1,14 @@ +[Unit] +Description=Tarzan Trust Agent +After=network.target +StartLimitIntervalSec=0 + +[Service] +Type=simple +Restart=always +RestartSec=1 +User=root +ExecStart=/opt/jane/tarzan --sys + +[Install] +WantedBy=multi-user.target diff --git a/docker-compose.yml b/etc/deprecated/docker-compose.yml.forkeylime similarity index 100% rename from docker-compose.yml rename to etc/deprecated/docker-compose.yml.forkeylime diff --git a/etc/deprecated/exampleDB/example_elements.json b/etc/deprecated/exampleDB/example_elements.json new file mode 100644 index 0000000..78c6c4a --- /dev/null +++ b/etc/deprecated/exampleDB/example_elements.json @@ -0,0 +1,414 @@ +{ + "_id": { + "$oid": "672fa0f605abda20c354f35e" + }, + "itemid": "d1b09fae-c996-4b4c-9678-0724cf15fc8c", + "name": "Local VM", + "description": "Local VM", + "endpoints": { + "a01rest": { + "endpoint": "http://127.0.0.1:8530", + "protocol": "A10HTTPRESTv2" + }, + "ratsd": { + "endpoint": "http://127.0.0.1:8888", + "protocol": "RATSD" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "", + "ekcerthandle": "", + "ek": { + "handle": "", + "public": "" + }, + "ak": { + "handle": "", + "public": "" + } + }, + "uefi": { + "eventlog": "" + }, + "ima": { + "asciilog": "" + }, + "txt": { + "log": "" + }, + "host": { + "os": "Linux", + "arch": "amd64", + "hostname": "Debian" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} +{ + "_id": { + "$oid": "673ee6b5a04eaf1a6a212b12" + }, + "itemid": "4921af2b-e1af-456e-9e21-4b5df5d72e04", + "name": "Debian Test UEFI VM", + "description": "Debian Test UEFI VM on the host Windows Box", + "endpoints": { + "a01rest": { + "endpoint": "http://192.168.1.44:8530", + "protocol": "A10HTTPRESTv2" + }, + "a10rest_2": { + "endpoint": "http://192.168.1.111:8530", + "protocol": "A10HTTPRESTv2" + }, + "ratsd": { + "endpoint": "http://192.168.1.110:8531", + "protocol": "RATSD" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "", + "ek": { + "handle": "0x81000002", + "public": "" + }, + "ak": { + "handle": "0x81000003", + "public": "" + } + }, + "uefi": { + "eventlog": "" + }, + "ima": { + "asciilog": "/sys/kernel/security/ima/ascii_runetime_measurements" + }, + "txt": { + "log": "" + }, + "host": { + "os": "Linux", + "arch": "amd64", + "hostname": "debiantpmuefi" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} +{ + "_id": { + "$oid": "67618d278d0be08a4f39276a" + }, + "itemid": "85e4c35d-1dd7-4e1c-9b66-7da445e859ee", + "name": "Debian Test UEFI VM 2 IMA", + "description": "Debian Test UEFI VM + IMA on the host Windows Box", + "endpoints": { + "tarzan": { + "endpoint": "http://192.168.1.99:8530", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "", + "ek": { + "handle": "0x810100EE", + "public": "" + }, + "ak": { + "handle": "0x810100AA", + "public": "" + } + }, + "uefi": { + "eventlog": "" + }, + "ima": { + "asciilog": "/sys/kernel/security/ima/ascii_runetime_measurements" + }, + "txt": { + "log": "" + }, + "host": { + "os": "Linux", + "arch": "amd64", + "hostname": "debiantpmuefi2" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} +{ + "_id": { + "$oid": "677be729492c2d476df55c63" + }, + "itemid": "fc6c5da8-2e1d-49cb-9f41-63608e9ad25f", + "name": "sample3", + "description": "this is a longer description", + "endpoints": { + "ratds": { + "endpoint": "http://192.168.1.44:8531", + "protocol": "RATSD" + }, + "tarzan": { + "endpoint": "http://192.168.1.44:8530", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "0x1C000002", + "ek": { + "handle": "0x810100EE", + "public": "", + "name": "AAtEscFypbeUoX1faZLQLJytoSvT+6+T9H9YQrt632Waiw==" + }, + "ak": { + "handle": "0x810100AA", + "public": "", + "name": "AAuipxHb3J11ao8eySYRV9yU+MHqreRe/lfegvB/0xi+4w==" + } + }, + "uefi": { + "eventlog": "" + }, + "ima": { + "asciilog": "/sys/kernel/security/ima/ascii_runtime_measurements" + }, + "txt": { + "log": "" + }, + "host": { + "os": "linux", + "arch": "amd64", + "hostname": "debiantpmuefi" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} +{ + "_id": { + "$oid": "677ed91852d08ddb09554f89" + }, + "itemid": "b23773e3-dccb-437d-bb00-b10842ac1fa0", + "name": "Protectli NUC", + "description": "Protectli NUC running Mosquitto and Jane", + "endpoints": { + "tarzan1": { + "endpoint": "http://192.168.1.8:8530", + "protocol": "A10HTTPRESTv2" + }, + "tarzan2": { + "endpoint": "http://192.168.1.9:8530", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "ima": { + "asciilog": "/sys/kernel/security/ima/ascii_runetime_measurements" + }, + "host": { + "os": "Linux", + "arch": "amd64", + "hostname": "server1" + } +} +{ + "_id": { + "$oid": "6799322c493acc36b81ef1c0" + }, + "itemid": "96320750-2bf4-47e3-932d-44fccb3ab9a5", + "name": "PIHole", + "description": "PiHole Machine", + "endpoints": { + "a10rest": { + "endpoint": "http://192.168.1.11:8530", + "protocol": "A10HTTPRESTv2" + }, + "proxied_a10rest": { + "endpoint": "http://192.168.1.9:8531/pihole", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "", + "ek": { + "handle": "0x810100EE", + "public": "" + }, + "ak": { + "handle": "0x810100AA", + "public": "" + } + }, + "uefi": { + "eventlog": "" + }, + "ima": { + "asciilog": "/sys/kernel/security/ima/ascii_runetime_measurements" + }, + "txt": { + "log": "" + }, + "host": { + "os": "Linux", + "arch": "amd64", + "hostname": "debiantpmuefi" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} +{ + "_id": { + "$oid": "67a251a758c27adad04e8b45" + }, + "itemid": "aa0d46ac-e343-4ee9-8b8b-fc19f922c902 ", + "name": "Pi 1", + "description": "The original Pi1B with arm6", + "endpoints": { + "a10rest": { + "endpoint": "http://192.168.1.14:8530", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "", + "ek": { + "handle": "0x810100EE", + "public": "" + }, + "ak": { + "handle": "0x810100AA", + "public": "" + } + }, + "host": { + "os": "Linux", + "arch": "arm6", + "hostname": "pi1" + } +} +{ + "_id": { + "$oid": "67e64da182e58c980557a06e" + }, + "itemid": "fb98da7a-f1d4-4f02-9f00-b2ba062bbda8", + "name": "BluetoothCollector", + "description": "BluetoothCollector Machine", + "endpoints": { + "a10rest": { + "endpoint": "http://192.168.1.12:8530", + "protocol": "A10HTTPRESTv2" + }, + "proxied_a10rest": { + "endpoint": "http://192.168.1.9:8531/pihole", + "protocol": "A10HTTPRESTv2" + } + }, + "tags": null, + "sshkey": { + "key": "", + "timeout": 0, + "username": "" + }, + "tpm2": { + "device": "/dev/tpmrm0", + "ekcerthandle": "", + "ek": { + "handle": "0x810100EE", + "public": "" + }, + "ak": { + "handle": "0x810100AA", + "public": "" + } + }, + "host": { + "os": "Linux", + "arch": "amd6", + "hostname": "bluetoothcollector" + }, + "mrcoordinator": { + "certs": null + }, + "mrmarbleinstance": { + "expectednonce": "", + "requestdata": "", + "requestsignature": "" + } +} diff --git a/etc/deprecated/exampleDB/example_evs.json b/etc/deprecated/exampleDB/example_evs.json new file mode 100644 index 0000000..4c46932 --- /dev/null +++ b/etc/deprecated/exampleDB/example_evs.json @@ -0,0 +1,72 @@ +{ + "_id": { + "$oid": "6730915297b753b860103e7d" + }, + "itemid": "b4601308-997c-415d-be4b-40d3f6372a8a", + "name": "zog", + "description": "arrl", + "elementid": "d1b09fae-c996-4b4c-9678-0724cf15fc8c", + "intentid": "std::intent::sha256::grubfull", + "evs": { + "attestedValue": "****", + "firmwareVersion": "****" + } +} +{ + "_id": { + "$oid": "673092b65b0452dcfbdd7e8d" + }, + "itemid": "6d9c6aa9-99d8-4387-bd31-a2c2c687c3a0", + "name": "fred1", + "description": "fred1jfdkajdflali'skjgl", + "elementid": "d1b09fae-c996-4b4c-9678-0724cf15fc8c", + "intentid": "std::intent::sha256::crtm::firmware", + "evs": { + "attestedValue": "****", + "firmwareVersion": "****" + } +} +{ + "_id": { + "$oid": "673ee8620ebbc5dd3cca4e5a" + }, + "itemid": "3a00ca15-96cd-4b9a-b6ab-5d12c48e76b5", + "name": "DebianTPMUEFItestCRTM", + "description": "DebianTPMUEFItestCRTM", + "elementid": "4921af2b-e1af-456e-9e21-4b5df5d72e04", + "intentid": "std::intent::sha256::crtm::pcr0", + "endpointname": "a10rest_2", + "evs": { + "attestedValue": "QWxMK1BtT2pUWWFDOHp6Y3EwcXI2Sy9IVjlac0g5ZDJpVkpvU1lza0hyTT0=", + "firmwareVersion": "2019102300163636" + } +} +{ + "_id": { + "$oid": "673f8adcd91a867cab8620ab" + }, + "itemid": "240cd0b0-e773-4a22-8412-4b693546bd39", + "name": "DebianTPMUEFItestSRTM", + "description": "SRTM for debian test Uefi VM SRTM + bootloader", + "elementid": "4921af2b-e1af-456e-9e21-4b5df5d72e04", + "intentid": "std::intent::sha256::crtm::srtmbootloader", + "evs": { + "firmwareVersion": "2312897626142815798", + "attestedValue": "4oYS7lJNG9aGnmZszzZm57Maq1BjfHyfm6byfjOQCMg=" + } +} +{ + "_id": { + "$oid": "67fba63aeb84c9865916d84f" + }, + "itemid": "fc10c8e8-5e5a-4e87-8b2f-120da645304c", + "name": "DebianTPMUEFItestCRTM (a01)", + "description": "DebianTPMUEFItestCRTM for a01rest endpoint", + "elementid": "4921af2b-e1af-456e-9e21-4b5df5d72e04", + "intentid": "std::intent::sha256::crtm::pcr0", + "endpointname": "a01rest", + "evs": { + "attestedValue": "AlL+PmOjTYaC8zzcq0qr6K/HV9ZsH9d2iVJoSYskHrM=", + "firmwareVersion": "2312897626142815798" + } +} diff --git a/etc/deprecated/exampleDB/example_oos.json b/etc/deprecated/exampleDB/example_oos.json new file mode 100644 index 0000000..d521b44 --- /dev/null +++ b/etc/deprecated/exampleDB/example_oos.json @@ -0,0 +1,54 @@ +{ + "_id": { + "$oid": "67311360d6f8dad85dc1e4fe" + }, + "value": "a", + "longdescription": "d\r\ne", + "shortdescription": "c", + "type": "b" +} +{ + "_id": { + "$oid": "6749ac509a898426db911395" + }, + "value": "80251604ae3990c30043327ea254dce73b3c8866a0c9c6c02263ef5ea3d38599", + "longdescription": "VirtualBox UEFI CRTM", + "shortdescription": "VirtualBox UEFI CRTM", + "type": "SHA256" +} +{ + "_id": { + "$oid": "67e64fec521820de6c0c09f9" + }, + "value": "0000000000000000000000000000000000000000", + "longdescription": "Likely to be an uninitialised PCR", + "shortdescription": "Uninitialised PCR", + "type": "SHA1" +} +{ + "_id": { + "$oid": "67e65084521820de6c0c09fa" + }, + "value": "ffffffffffffffffffffffffffffffffffffffff", + "longdescription": "Unitialised PCR for certain PCRs", + "shortdescription": "Unitialised PCR for certain PCRs", + "type": "SHA1" +} +{ + "_id": { + "$oid": "67e650a5521820de6c0c09fb" + }, + "value": "0000000000000000000000000000000000000000000000000000000000000000", + "longdescription": "Uninitialised PCR", + "shortdescription": "Uninitialised PCR", + "type": "SHA256" +} +{ + "_id": { + "$oid": "67e650c0521820de6c0c09fc" + }, + "value": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "longdescription": "Unitialised PCR for certain PCRs", + "shortdescription": "Unitialised PCR for certain PCRs", + "type": "SHA256" +} diff --git a/etc/experimental/janeway/assets/Antonio-Bold.woff b/etc/experimental/janeway/assets/Antonio-Bold.woff new file mode 100644 index 0000000..6f24591 Binary files /dev/null and b/etc/experimental/janeway/assets/Antonio-Bold.woff differ diff --git a/etc/experimental/janeway/assets/Antonio-Bold.woff2 b/etc/experimental/janeway/assets/Antonio-Bold.woff2 new file mode 100644 index 0000000..e772d58 Binary files /dev/null and b/etc/experimental/janeway/assets/Antonio-Bold.woff2 differ diff --git a/etc/experimental/janeway/assets/Antonio-Regular.woff b/etc/experimental/janeway/assets/Antonio-Regular.woff new file mode 100644 index 0000000..19027a5 Binary files /dev/null and b/etc/experimental/janeway/assets/Antonio-Regular.woff differ diff --git a/etc/experimental/janeway/assets/Antonio-Regular.woff2 b/etc/experimental/janeway/assets/Antonio-Regular.woff2 new file mode 100644 index 0000000..2c89826 Binary files /dev/null and b/etc/experimental/janeway/assets/Antonio-Regular.woff2 differ diff --git a/etc/experimental/janeway/assets/jquery-3-7-0.min.js b/etc/experimental/janeway/assets/jquery-3-7-0.min.js new file mode 100644 index 0000000..e7e29d5 --- /dev/null +++ b/etc/experimental/janeway/assets/jquery-3-7-0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.7.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.0",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},R=function(){V()},M=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&z(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function X(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&M(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function U(a){return F(function(o){return o=+o,F(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function z(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",R),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||I.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=I.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",le.option=!!xe.lastChild;var ke={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n",""]);var je=/<|&#?\w+;/;function Ae(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function Me(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="
",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),v(t)&&(t=t.call(e,n,ce.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===ce.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return R(this,function(e,t,n){var r;if(y(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return R(this,function(e,t,n){var r;return y(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),ce.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){ce.fn[n]=function(e,t){return 0 *:first-child, +article > *:first-child { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3 { + margin-top: 1.15rem; + margin-bottom: 1rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; +} + +h1 { + font-size: clamp(2rem, 1.04rem + 3.84vw, 3.2rem); + text-align: right; +} + +h2 { + font-size: clamp(1.6rem, 1.04rem + 2.24vw, 2.3rem); +} + +h3 { + font-size: clamp(1.4rem, 1.08rem + 1.28vw, 1.8rem); +} + +p { + margin-block: 1rem; +} + +.caption { + margin-top: .5rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 40px; +} + +.postmeta { + margin: .25rem 0 1.25rem 0; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +code { + font-family: monospace; + font-size: .9rem; + color: #f70; +} + +hr { + margin: 1rem 0; + height: 6px; + border: none; + background-color: #c8f; + border-radius: 3px; +} + +blockquote { + margin: 30px 40px; + border-left: 4px solid #c8f; + padding-left: 20px; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-bigger, /* go-bigger is for backwards compatibility */ +.go-big { + font-size: clamp(1.14rem, 0.94rem + 0.81vw, 1.4rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 4rem; +} + +strong { + font-weight: bold; +} + +.blink-slower, /* blink-slower is for backwards compatibility */ +.blink-slow { + animation: blink 3s infinite; + animation-delay: 1s; +} + +.blink { + animation: blink 2s infinite; + animation-delay: 1s; +} + +.blink-faster, /* blink-faster is for backwards compatibility */ +.blink-fast { + animation: blink 1s infinite; + animation-delay: 1s; +} + +/* Images */ + +.pics-right { + float: right; + margin: 10px 0 20px 20px; +} + +.pics-left { + float: left; + margin: 10px 20px 20px 0; +} + +.pics { + display: block; + margin: 1.5rem auto 0 auto; +} + +.border { + padding: 10px; + border: 2px solid #c8f; +} + +.lcars-list { + margin-top: 1rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-bottom: .4rem; + padding-left: 2rem; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 30px; + height: 20px; + border-radius: 50%; + background-color: #c8f; + position: absolute; + top: 10px; + left: 0; +} + +/* Buttons for main content area, NOT main top navigation */ + +.buttons { + margin-top: 1.5rem; + display: flex; + flex-wrap: wrap; +} + +.jc-space-between { + justify-content: space-between; +} + +.jc-center { + justify-content: center; +} + +.jc-flex-end { + justify-content: flex-end; +} + +.jc-space-around { + justify-content: space-around; +} + +.jc-space-evenly { + justify-content: space-evenly; +} + +.buttons a { + display: block; + margin: 5px; + width: 210px; + height: 72px; + padding-top: 34px; + padding-right: 25px; + background-color: #c8f; + border-radius: 100vmax; /* 26px */ + text-align: right; + line-height: normal; + text-decoration: none; + font-size: var(--sub-fonts); + font-weight: bold; + text-transform: uppercase; + color: #000; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.buttons a.two-rows { + padding-top: 12px; +} + +.sidebar-buttons a { + display: block; + text-decoration: none; + text-align: right; + border-bottom: 5px solid #000; + padding: 20px 10px 20px 2px; + background-color: #d44; + text-transform: uppercase; + color: #000; +} + +@media (max-width: 650px) { + + .buttons a { + font-size: .9rem; + } + + .buttons a.two-rows { + padding-top: 13px; +} + + .sidebar-buttons a { + text-align: center; + padding-block: 9px; + } +} + +.lcars-bar { + margin: 40px auto; + height: 22px; + background-color: #c8f; + border-right: 20px solid #94f; + border-left: 20px solid #94f; + border-radius: 100vmax; + padding-inline: 5px; + position: relative; +} + +.lcars-bar::before { + content: ''; + display: block; + height: 22px; + width: 100%; + border-right: 8px solid #000; + border-left: 8px solid #000; + position: absolute; + top: 0; + left: 0; + z-index: 1; +} + +.lcars-text-bar { + display: flex; + position: relative; + margin-top: 1.5rem; + margin-bottom: 1.2rem; + overflow: visible; + border-radius: 14px; + height: 32px; + background-color: #ffaa90; + border-right: 28px solid #dbf; + border-left: 28px solid #d44; +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar span { + position: absolute; + top: -5px; + background-color: #000; + height: 40px; + overflow: visible; + padding-inline: 10px; + font-size: 36px; + line-height: 36px; + text-transform: uppercase; +} + +.lcars-text-bar::before { + content: ''; + background-color: #000; + display: block; + width: 10px; + height: 32px; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: #000; + display: block; + width: 10px; + height: 32px; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +@media (max-width: 650px) { + + .lcars-text-bar { + border-radius: 10px; + height: 24px; + border-right-width: 20px; + border-left-width: 20px; + } + + .lcars-text-bar span { + position: absolute; + top: -3px; + height: 30px; + padding-inline: 5px; + font-size: 26px; + line-height: 26px; + } + + .lcars-text-bar::before, + .lcars-text-bar::after { + width: 5px; + height: 24px; + } + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + top: 5px; + transform: scale(80%); + } +} + +footer { + display: flex; + margin-top: clamp(50px, 6vw, 125px); + padding-block: 12px ; + background: linear-gradient(#78f 50%, #d44 50%); + border-radius: 0 20px 20px 0; + overflow: hidden; + position: relative; + z-index: 1; +} + +footer::before { + content: ''; + background-color: #000; + display: block; + width: 5px; + height: 100vh; + position: absolute; + top: 0; + left: 25%; + overflow: hidden; +} + +footer::after { + content: ''; + background-color: #000; + display: block; + width: 2px; + height: 100vh; + position: absolute; + top: 0; + left: -1px; + overflow: hidden; +} + +.footer-panel { + width: 12%; + max-width: 130px; + height: 100px; + margin: auto; + padding-top: 10px; + padding-left: .4rem; + background-color: #ffaa90; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; +} + +.footer-inside { + flex: 1; + min-height: 180px; + background-color: #000; + border-radius: 0 20px 20px 0; + padding: 1.5rem 1rem; + z-index: 2; +} + +.footer-inside::before { + content: ''; + background-color: #78f; + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + top: 17px; + left: 1px; + overflow: hidden; +} + +.footer-inside::after { + content: ''; + background-color: #d44; + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + bottom: 12px; + left: 1px; + overflow: hidden; +} + +.footer-text { + display: flex; + flex-direction: column; + min-height: 146px; + align-items: center; + justify-content: center; + gap: .75rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.footer-text > * { + margin: 0; +} + +@media (max-width: 600px) { + + footer::before { + left: 40%; + } +} + +/* Grouped Media */ + +@media (max-width: 1240px) { + + .bar-1, + .bar-6 { + width: 320px; + } + + .panel-4 { + padding-top: 115px; + } + +} + +@media (max-width: 1100px) { + + .left-frame-top { + width: 180px; + min-width: 180px; + border-radius: 0 0 0 100px; + } + + .left-frame { + width: 180px; + min-width: 180px; + border-radius: 100px 0 0 0; + } + + .scroll-top a { + width: 180px; + } + + .bar-1, + .bar-6 { + width: 290px; + } + + .left-frame { + padding-top: 70px; + } + +} + +@media (max-width: 890px) { + + .left-frame-top, + .left-frame { + width: 150px; + min-width: 150px; + } + + .left-frame-top { + border-radius: 0 0 0 80px; + } + + .left-frame { + border-radius: 80px 0 0 0; + } + + .scroll-top a { + width: 150px; + padding: 10px 0 0 0; + text-align: center; + } + + .sutrebor { + margin: 4px 4px 19px 69px; + } + + .bar-1, + .bar-6 { + width: 180px; + } + + .bar-3, + .bar-8 { + width: 180px; + } + + blockquote { + margin-right: 0; + margin-left: 25px; + } + + .pics-right, + .pics-left { + float: none; + margin: 20px 0 20px 0; + } + + .pics-right img, + .pics-left img { + display: block; + margin: 0 auto; + } +} + +@media (max-width: 650px) { + + .left-frame-top, + .left-frame { + width: 110px; + min-width: 110px; + } + + .left-frame-top { + border-radius: 0 0 0 60px; + } + + .left-frame { + border-radius: 60px 0 0 0; + } + + .scroll-top a { + width: 110px; + height: 110px; + } + + .bar-panel { + height: 16px; + } + + .first-bar-panel { + margin-top: 15px; +} + + .bar-1, + .bar-2, + .bar-3, + .bar-4, + .bar-5, + .bar-6, + .bar-7, + .bar-9, + .bar-10 { + height: 16px; + } + + .bar-1, + .bar-6 { + width: 130px; + } + + .bar-3, + .bar-8 { + width: 130px; + } + + .bar-5, + .bar-10 { + width: 25px; + } +} + +@media (max-width: 500px) { + + body { + padding: 0; + } + + .wrap { + padding-left: 0; + } + + .left-frame-top, + .left-frame { + width: 60px; + min-width: 60px; + font-size: .8rem; + } + + .left-frame-top { + border-radius: 0 0 0 26px; + } + + .left-frame { + border-radius: 26px 0 0 0; + padding-top: 50px; + } + + .scroll-top a { + width: 60px; + } + + .panel-1 a { + padding-top: 30px; + } + + .panel-2 { + padding-bottom: 15px; + border-bottom: 5px solid #000; + background-color: #78f; + } + + .panel-6 { + padding-top: 150px; + } + + .hop { + display: none; + } + + .bar-panel { + height: 10px; + } + + .bar-1, + .bar-2, + .bar-3, + .bar-4, + .bar-5, + .bar-6, + .bar-7, + .bar-9, + .bar-10 { + height: 10px; + } + + .bar-3, + .bar-8 { + width: 80px; + } + + .bar-2, + .bar-7 { + width: 25px; + } + + .bar-8 { + height: 5px; + } + + #gap { + margin-top: 5px; + } + + .panel-4 { + padding-top: 65px; + } + + p.indent { + padding-left: 20px; + } + + blockquote { + margin: 25px 0 25px 20px; + } +} + +@media (max-width: 388px) { + + .bar-1, + .bar-6 { + width: 90px; + } +} \ No newline at end of file diff --git a/etc/experimental/janeway/assets/lcars-ultra-nemesis-blue.css b/etc/experimental/janeway/assets/lcars-ultra-nemesis-blue.css new file mode 100644 index 0000000..b271b01 --- /dev/null +++ b/etc/experimental/janeway/assets/lcars-ultra-nemesis-blue.css @@ -0,0 +1,2158 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Ultra - Nemesis Blue Theme + Version 23-B + By Jim Robertus www.thelcars.com + Modified: 2023 Sep 8 + +*/ + +:root { + font-size: 1.5rem; + --section-2-color: #11e; /* 33e */ + color-scheme: dark; + --sub-fonts: .8rem; +} + +@media (max-width: 650px) { + :root { + font-size: 1.2rem; + } +} + +*, *:after, *:before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +body { + display: flex; + padding-block: 5px; + background-color: #000; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: #26f; +} + +a { + color: #58f; + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +@keyframes colorchange { + 0% {color: #26f} + 25% {color: #26f} + 50% {color: #26f} + 75% {color: #26f} + 80% {color: #000} + 90% {color: #000} + 100% {color: #def} +} + +/* Begin Ultra elements */ + +.wrap-everything { + display: flex; + width: 100%; + column-gap: 12px; +} + +#column-1 { + width: 350px; + padding: 10px 10px 10px 20px; + transition: 800ms; +} + +#column-2 { + width: 200px; + min-width: 200px; + background-color: var(--section-2-color); + text-align: right; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; + transition: 800ms; + z-index: 2; +} + +#column-2 a { + color: #000; + text-decoration: none; +} + +#column-3 { + flex: 1; + margin-inline: auto; +} + +.wrap { + display: flex; + margin-inline: auto; + padding-left: 5px; + padding-right: 10px; + overflow: hidden; +} + +.wrap-standard { + max-width: 1440px; +} + +.wrap-standard-full-width { + width: 100%; +} + +@media (max-width: 1800px) { + #column-1 { + margin-left: -350px; + } +} + +@media (max-width: 1640px) { + #column-2 { + margin-left: -200px; + } + + .wrap-everything { + column-gap: 0; + } +} + +.lcars-frame { + display: flex; + min-height: 280px; + position: relative; + --frame-color: #25f; +} + +.frame-col-1 { + width:20px; + height: 280px; + background: var(--frame-color); + border-radius: 16px 0 0 16px; + position: relative; +} + +.frame-col-1:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + background-color: var(--frame-color); + position: absolute; + top: 40px; + left: 0; +} + +.frame-col-1-cell-a { + width: 14px; + height: 65px; + background-color: #c66; + border-left: 4px solid #000; + border-bottom: 4px solid #000; + position: absolute; + top: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-b { + width: 14px; + height: 70px; + background-color: #8bf; + border-left: 4px solid #000; + position: absolute; + top: 110px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-c { + width: 14px; + height: 65px; + background-color: #c23; + border-top: 4px solid #000; + border-left: 4px solid #000; + position: absolute; + bottom: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-blocks:before { + content: ''; + display: block; + width: 10px; + height: 3px; + background-color: #000; + position: absolute; + top: 54px; + left: 0; +} + +.frame-col-2 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-2:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: #000; + border-radius: 10px 0 0 10px; + position: absolute; + top: 20px; + left: 0; +} + +.frame-col-3 { + display: flex; + width: 240px; + height: 280px; + align-items: center; + justify-content: center; +} + +.frame-col-4 { + width:20px; + height: 280px; + background-color: var(--frame-color); + position: relative; +} + +.frame-col-4:before { + content: ''; + display: block; + width: 20px; + height: 240px; + background-color: #000; + border-radius: 0 10px 10px 0; + position: absolute; + top: 20px; + left: 0; +} + +.display-horizontal { + rotate: 90deg; +} + +.frame-col-5 { + width:20px; + height: 280px; + background-color: var(--frame-color); + border-radius: 0 16px 16px 0; + padding-top: 40px; + position: relative; +} + +.frame-col-5:before { + content: ''; + display: block; + width: 20px; + height: 200px; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + background-color: var(--frame-color); +} + +.frame-col-5-cell-a { + width: 14px; + height: 65px; + background-color: #f83; + border-bottom: 4px solid #000; + border-right: 4px solid #000; + position: absolute; + top: 45px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-b { + width: 14px; + height: 70px; + background-color: #58f; + border-right: 4px solid #000; + position: absolute; + top: 110px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-c { + width: 14px; + height: 65px; + background-color: #fc9; + border-top: 4px solid #000; + border-right: 4px solid #000; + position: absolute; + bottom: 45px; + left: 0; + z-index: 2; +} + +.line { + height: 20px; + width: 12px; + background: linear-gradient(#600, #f20, #600); +} + +.line:nth-child(1) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(2) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(3) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(4) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(5) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(6) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(7) { + animation: animateLine2 1s 0.8s infinite; +} + +/* 8 & 9 are middle lines*/ + +.line:nth-child(8) { + animation: animateLine4 1s 0.9s infinite; +} + +.line:nth-child(9) { + animation: animateLine4 1s 1s infinite; +} + +.line:nth-child(10) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(11) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(12) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(13) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(14) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(15) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(16) { + animation: animateLine6 1s 0.2s infinite; +} + +@keyframes animateLine2 { + 0% { + height: 180px; + } + 50% { + height: 90px; + } + 100% { + height: 180px; + } +} + +@keyframes animateLine3 { + 0% { + height: 120px; + } + 50% { + height: 60px; + } + 100% { + height: 120px; + } +} + +@keyframes animateLine4 { + 0% { + height: 230px; + } + 50% { + height: 115px; + } + 100% { + height: 230px; + } +} + +@keyframes animateLine5 { + 0% { + height: 60px; + } + 50% { + height: 30px; + } + 100% { + height: 60px; + } +} + +@keyframes animateLine6 { + 0% { + height: 30px; + } + 50% { + height: 15px; + } + 100% { + height: 30px; + } +} + +.pillbox { + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 8px; + margin: 25px auto; + text-align: right; + font-size: var(--sub-fonts); +} + +.pill a { + display: inline-block; + width: 100%; + text-decoration: none; + color: #000; + font-weight: bold; + padding: 18px 15px 8px 4px; +} + +.pill-2 a { + display: inline-block; + width: 100%; + text-decoration: none; + color: #000; + font-weight: bold; + padding: 18px 15px 8px 4px; +} + +.pill:hover { + filter: brightness(115%); +} + +.pill:active { + filter: brightness(80%); +} + +.pill:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: #25f; +} + +.pill:nth-child(2) { + background-color: #58f; +} + +.pill:nth-child(3) { + border-radius: 100vmax 0 0 100vmax; + background-color: #58f; +} + +.pill:nth-child(4) { + background-color: #25f; +} + +.pill:nth-child(5) { + background-color: #11e; + border-radius: 100vmax 0 0 100vmax; +} + +.pill:nth-child(6) { + background-color: #11e; +} + +.pill-2:hover { + filter: brightness(115%); +} + +.pill-2:active { + filter: brightness(80%); +} + +.pill-2:nth-child(1) { + border-radius: 100vmax 0 0 100vmax; + background-color: #11e; +} + +.pill-2:nth-child(2) { + background-color: #58f; + border-radius: 0 100vmax 100vmax 0; + padding-right: 10px; +} + +.pill-2:nth-child(3) { + background-color: #000; +} + +.pill-2:nth-child(4) { + background-color: #25f; + border-radius: 0 100vmax 100vmax 0; + padding-right: 10px; +} + +.pill-2:nth-child(5) { + background-color: #f74; + border-radius: 100vmax 0 0 100vmax; +} + +.pill-2:nth-child(6) { + background-color: #fc9; + border-radius: 0 100vmax 100vmax 0; + padding-right: 10px; +} + +.lcars-list-2 ul { + list-style: none; +} + +.lcars-list-2 { + margin: 0 auto 50px auto; + padding-left: 5px; +} + +.lcars-list-2 li { + position: relative; + padding-bottom: 5px; + padding-left: 38px; + font-size: var(--sub-fonts); +} + +.lcars-list-2 li::before { + content: ''; + display: block; + width: 24px; + height: 14px; + border-radius: 50%; + background-color: #58f; + position: absolute; + top: 8px; + left: 0; +} + +.section-2-panel-a { + padding: 205px 10px 15px 0; + background-color: #58f; + border-bottom: 5px solid #000; +} + +.section-2-panel-b { + padding: 300px 10px 15px 0; + background-color: #58f; + border-bottom: 5px solid #000; +} + +.section-2-panel-c { + padding: 15px 10px 125px 0; + + border-bottom: 5px solid #000; +} + +.section-2-panel-d { + padding: 125px 10px 15px 0; + background-color: #f74; + border-bottom: 5px solid #000; +} + +.section-2-panel-e { + padding: 425px 10px 15px 0; + border-bottom: 5px solid #000; +} + +.section-2-buttons a { + display: block; + text-decoration: none; + text-align: right; + border-bottom: 5px solid #000; + padding: 30px 10px 15px 2px; + background-color: #25f; + text-transform: uppercase; + color: #000; +} + +.section-2-buttons a:nth-child(2) { + background-color: #ccdeff; +} + +/* End LCARS Ultra */ + +.scroll-top { + display: block; +} + +.scroll-top a { + display: none; + width: 200px; + height: 150px; + position: fixed; + bottom: 0; + text-decoration: none; + text-transform: uppercase; + text-align: right; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + padding: 20px 10px 0 2px; + background-color: #444a77; + font-size: .9rem; + font-weight: bold; + color: #000; +} + +.left-frame-top, +.left-frame { + width: 200px; + text-align: right; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; +} + +.left-frame-top { + background-color: #25f; + border-radius: 0 0 0 140px; +} + +.left-frame-top a, +.left-frame a { + text-decoration: none; + color: #000; +} + +.left-frame { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-top: 90px; + background-color: #25f; + border-radius: 140px 0 0 0; +} + +.panel-1 { + border-bottom: 5px solid #000; +} + +.panel-1 a { + display: block; + background-color: #ca8; + padding-top: 100px; + padding-right: 10px; + padding-bottom: 15px; + text-decoration: none; + color: #000; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.panel-2 a { + display: block; + padding: 30px 10px 15px 0; + border-bottom: 5px solid #000; + background-color: #ccdeff; +} + +.right-frame-top { + flex: 1; + position: relative; +} + +.right-frame-top:before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, #25f 50%, #000 50%); + position: absolute; + left: 0; + bottom: 22px; + z-index: -1; +} + +.right-frame-top:after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: #000; + border-radius: 0 0 0 56px; + position: absolute; + left: 0; + bottom: 22px; + z-index: -1; +} + +@media (max-width: 1100px) { + .right-frame-top:after { + border-radius: 0 0 0 40px; + } +} + +@media (max-width: 650px) { + .right-frame-top:before { + bottom: 16px; + } + + .right-frame-top:after { + border-radius: 0 0 0 30px; + bottom: 16px; + } +} + +@media (max-width: 500px) { + .right-frame-top:before { + bottom: 10px; + } + + .right-frame-top:after { + border-radius: 0 0 0 16px; + bottom: 10px; + } +} + +.banner { + padding-bottom: 25px; + padding-left: 5px; + text-align: right; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1.4rem, 0.28rem + 4.48vw, 3rem); + color: #8bf; +} + +.banner a { + color: #8bf; + text-decoration: none; +} + +@media (max-width: 500px) { + + .banner { + padding-top: 5px; + padding-bottom: 10px; + padding-left: 3px; + } +} + +.data-cascade-button-group { + display: flex; + justify-content: flex-end; + padding-left: 2vw; +} + +.cascade-wrapper { + flex: 1; + padding-right: 15px; +} + +@media (max-width: 800px) { + .cascade-wrapper { + display: none; + } +} + +.data-cascade { + font-size: .75rem; + line-height: 1; +} + +.row-1, +.row-2, +.row-3, +.row-4, +.row-5, +.row-6, +.row-7, +.row-8 { + display: flex; + justify-content: space-between; + overflow: hidden; + height: 21px; + color: #000; +} + +/* Data Cascade default pattern */ + +.data-cascade .row-1 { + animation: colorchange 3s infinite; animation-delay: .1s; +} + +.data-cascade .row-2 { + animation: colorchange 3s infinite; animation-delay: .2s; +} + +.data-cascade .row-3 { + animation: colorchange 4s infinite; animation-delay: .3s; +} + +.data-cascade .row-4 { + animation: colorchange 4s infinite; animation-delay: .4s; +} + +.data-cascade .row-5 { + animation: colorchange 4s infinite; animation-delay: .5s; +} + +.data-cascade .row-6 { + animation: colorchange 2s infinite; animation-delay: .6s; +} + +.data-cascade .row-7 { + animation: colorchange 2s infinite; animation-delay: .7s; +} + +.data-cascade .row-8 { + animation: colorchange 2s infinite; animation-delay: .8s; +} + + /* Niagara pattern */ + +.data-cascade#niagara .row-1 { + animation: colorchange 2s infinite; animation-delay: .1s; +} + +.data-cascade#niagara .row-2 { + animation: colorchange 2s infinite; animation-delay: .2s; +} + +.data-cascade#niagara .row-3 { + animation: colorchange 2s infinite; animation-delay: .3s; +} + +.data-cascade#niagara .row-4 { + animation: colorchange 2s infinite; animation-delay: .4s; +} + +.data-cascade#niagara .row-5 { + animation: colorchange 2s infinite; animation-delay: .5s; +} + +.data-cascade#niagara .row-6 { + animation: colorchange 2s infinite; animation-delay: .6s; +} + +.data-cascade#niagara .row-7 { + animation: colorchange 2s infinite; animation-delay: .7s; +} + +.data-cascade#niagara .row-8 { + animation: colorchange 2s infinite; animation-delay: .8s; +} + +/* Frozen pattern */ + +.data-cascade#frozen .row-1 { + animation: none; + color: #26f; +} + +.data-cascade#frozen .row-2 { + animation: none; + color: #26f; + opacity: .8; +} + +.data-cascade#frozen .row-3 { + animation: none; + color: #8bf; +} + +.data-cascade#frozen .row-4 { + animation: none; + color: #26f; +} + +.data-cascade#frozen .row-5 { + animation: none; + color: #26f; +} + +.data-cascade#frozen .row-6 { + animation: none; + color: #58f; +} + +.data-cascade#frozen .row-7 { + animation: none; + color: #58f; +} + +.data-cascade#frozen .row-8 { + animation: none; + color: #def; +} + +.dc1, +.dc2, +.dc3, +.dc4, +.dc44, +.dc5, +.dc55, +.dc6, +.dc7, +.dc77, +.dc8, +.dc9, +.dc99, +.dc10, +.dc100, +.dc11, +.dc12, +.dc13, +.dc14, +.dc15, +.dc150 { + flex: 1; + overflow: hidden; + text-align: right; + white-space: nowrap; +} + +@media (max-width: 2050px) { + .dc4, + .dc7 { + display: none; + } +} + +@media (max-width: 1950px) { + .dc5, + .dc9, + .dc10 { + display: none; + } +} + +@media (min-width: 1640px) { + .dc15 { + display: none; + } +} + +@media (max-width: 1400px) { + .dc150 { + display: none; + } +} + +@media (max-width: 1200px) { + .dc44, + .dc77, + .dc55, + .dc99, + .dc100 { + display: none; + } +} + +@media (max-width: 1150px) { + .dc15 { + display: none; + } +} + +@media (max-width: 1020px) { + .dc2, + .dc3, + .dc6 { + display: none; + } +} + +@media (max-width: 920px) { + .dc11, + .dc14 { + display: none; + } +} + +nav { + display: flex; + flex-wrap: wrap; + max-width: 660px; + justify-content: flex-end; +} + +#nav-standard { + max-width: 450px; +} + +nav a, +#blank { + display: block; + width: 210px; + height: 72px; + margin: 5px; + padding-top: 30px; + padding-right: 25px; + border-radius: 100vmax; + background-color: #58f; + text-align: right; + line-height: normal !important; + text-decoration: none; + text-transform: uppercase; + font-size: .9rem; + font-weight: bold; + color: #000; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +#b-one { + background-color: #58f; +} + +#nav-standard #b-one { + background-color: #25f; +} + +#b-two { + background-color: #c66; +} + +#blank { + background-color: black; +} + +#b-three { + background-color: #25f; +} + +#nav-standard #b-three { + background-color: #fc9; +} + +#b-four { + background-color: #fc9; +} + +#b-five { + background-color: #c23; +} + +nav a:hover { + animation: none; +} + +@media (max-width: 1450px) { + nav { + max-width: 450px; + } + + nav .go-away, + #blank { + display: none; + } + + #b-three { + background-color: #fc9; + } + + #b-four { + background-color: #25f; + } +} + +@media (max-width: 650px) { + + nav a { + width: 164px; + height: 54px; + padding-top: 18px; + padding-right: 15px; + } + + nav { + justify-content: flex-end; + max-width: 100%; + } +} + +@media (max-width: 420px) { + + nav a { + margin: 4px; + width: 148px; + } +} + +@media (max-width: 395px) { + nav a { + width: 140px; + } +} + +.floor-text { + min-height: 70px; + padding-top: 10px; + padding-bottom: 10px; + font-size: 1.5rem; + text-align: right; + text-transform: uppercase; + color: #58f; +} + +.bar-panel { + display: flex; + height: 22px; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-9, +.bar-10 { + height: 22px; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-6, +.bar-7, +.bar-8, +.bar-9 { + border-right: 5px solid #000; +} + +.bar-1, +.bar-6 { + transition: width 1s; +} + +.bar-1 { + width: 433px; + background-color: #25f; +} + +.bar-2 { + width: 40px; + background-color: #fc9; +} + +.bar-3 { + width: 200px; + background-color: #58f; +} + +.bar-4 { + flex: 1; + background-color: #11e; +} + +.bar-5 { + width: 50px; + background-color: #444a77; +} + +.bar-6 { + width: 433px; + background-color: #25f; +} + +.bar-7 { + width: 40px; + background-color: #f83; +} + +.bar-8 { + width: 200px; + height: 11px; + background-color: #ccdeff; +} + +.bar-9 { + flex: 1; + background-color: #25f; +} + +.bar-10 { + width: 50px; + background-color: #444a77; +} + +/* Bottom half */ + +#gap { + margin-top: 10px; +} + +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7, +.panel-8 { + padding-right: 10px; + border-bottom: 5px solid #000; +} + +.panel-3 { + Padding-top: 15px; + padding-bottom: 15px; +} + + +.panel-4 { + Padding-top: 180px; + padding-bottom: 15px; + background-color: #25f; +} + +.panel-5 { + padding-block: 25px; + background-color: #58f; +} + +.panel-6 { + padding: 230px 10px 15px 0; + Padding-top: ; + padding-bottom: ; + background-color: #25f; +} + +.panel-7 { + padding-top: 15px; + padding-bottom: 300px; + +} + +.panel-8 { + Padding-top: 15px; + padding-bottom: 110px; + background-color: #ccdeff; +} + +.panel-9 { + Padding-top: 15px; + padding-right: 10px; + padding-bottom: 170px; + background-color: #25f; +} + +.panel-10 { + border-top: 5px solid #000; + + Padding-top: 15px; + padding-right: 10px; + padding-bottom: 300px; +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame:before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, #25f 50%, #000 50%); + position: absolute; + left: 0; + top: 22px; + z-index: -1; +} + +.right-frame:after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: #000; + border-radius: 56px 0 0 0; + position: absolute; + left: 0; + top: 22px; + z-index: -1; +} + +@media (max-width: 1100px) { + .right-frame:after { + border-radius: 40px 0 0 0; + } +} + +@media (max-width: 650px) { + .right-frame:before { + top: 16px; + } + + .right-frame:after { + border-radius: 30px 0 0 0; + top: 16px; + } +} + +@media (max-width: 500px) { + .right-frame:before { + top: 10px; + } + + .right-frame:after { + border-radius: 16px 0 0 0; + top: 10px; + } +} + +main { + padding-top: 2vw; + padding-bottom: 50px; + padding-left: clamp(20px, 3vw, 50px); +} + +@media (min-width: 1400px) { + main { + padding-top: 25px; + } +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3 { + margin-top: 1.15rem; + margin-bottom: 1rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; + color: #8bf; +} + +h1 { + font-size: clamp(2rem, 1.04rem + 3.84vw, 3.2rem); + text-align: right; +} + +h2 { + font-size: clamp(1.6rem, 1.04rem + 2.24vw, 2.3rem); +} + +h3 { + font-size: clamp(1.4rem, 1.08rem + 1.28vw, 1.8rem); +} + +p { + margin-block: 1rem; +} + +.caption { + margin-top: .5rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 40px; +} + +.postmeta { + margin: .25rem 0 1.25rem 0; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +code { + font-family: monospace; + font-size: .9rem; + color: #9d6; +} + +hr { + margin: 1rem 0; + height: 6px; + border: none; + background-color: #25f; + border-radius: 3px; +} + +blockquote { + margin: 30px 40px; + border-left: 4px solid #26f; + padding-left: 20px; +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-bigger, /* go-bigger is for backwards compatibility */ +.go-big { + font-size: clamp(1.14rem, 0.94rem + 0.81vw, 1.4rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 4rem; +} + +strong { + font-weight: bold; +} + +.blink-slower, /* blink-slower is for backwards compatibility */ +.blink-slow { + animation: blink 3s infinite; + animation-delay: 1s; +} + +.blink { + animation: blink 2s infinite; + animation-delay: 1s; +} + +.blink-faster, /* blink-faster is for backwards compatibility */ +.blink-fast { + animation: blink 1s infinite; + animation-delay: 1s; +} + +/* Images */ + +.pics-right { + float: right; + margin: 10px 0 20px 20px; +} + +.pics-left { + float: left; + margin: 10px 20px 20px 0; +} + +.pics { + display: block; + margin: 1.5rem auto 0 auto; +} + +.border { + padding: 10px; + border: 2px solid #26f; +} + +.lcars-list { + margin-top: 1rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-bottom: .4rem; + padding-left: 2rem; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 30px; + height: 20px; + border-radius: 50%; + background-color: #25f; + position: absolute; + top: 10px; + left: 0; +} + +/* Buttons for main content area, NOT main top navigation */ + +.buttons { + margin-top: 1.5rem; + display: flex; + flex-wrap: wrap; +} + +.jc-space-between { + justify-content: space-between; +} + +.jc-center { + justify-content: center; +} + +.jc-flex-end { + justify-content: flex-end; +} + +.jc-space-around { + justify-content: space-around; +} + +.jc-space-evenly { + justify-content: space-evenly; +} + +.buttons a { + display: block; + margin: 0 8px 16px 8px; + width: 210px; + height: 72px; + padding-top: 34px; + padding-right: 25px; + background-color: #58f; + border-radius: 100vmax; /* 26px */ + text-align: right; + line-height: normal; + text-decoration: none; + font-size: var(--sub-fonts); + font-weight: bold; + text-transform: uppercase; + color: #000; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.buttons a.two-rows { + padding-top: 12px; +} + +.sidebar-buttons a { + display: block; + text-decoration: none; + text-align: right; + border-bottom: 5px solid #000; + padding: 20px 10px 20px 2px; + background-color: #25f; + text-transform: uppercase; + color: #000; +} + +.sidebar-buttons a:nth-child(1) { + background-color: #ccdeff; +} + +@media (max-width: 650px) { + + .buttons a { + font-size: .9rem; + } + + .buttons a.two-rows { + padding-top: 13px; +} + + .sidebar-buttons a { + text-align: center; + padding-block: 9px; + } +} + +.lcars-bar { + margin: 40px auto; + height: 22px; + background-color: #25f; + border-right: 20px solid #11e; + border-left: 20px solid #11e; + border-radius: 100vmax; + padding-inline: 5px; + position: relative; +} + +.lcars-bar::before { + content: ''; + display: block; + height: 22px; + width: 100%; + border-right: 8px solid #000; + border-left: 8px solid #000; + position: absolute; + top: 0; + left: 0; + z-index: 1; +} + +.lcars-text-bar { + display: flex; + position: relative; + margin-top: 1.5rem; + margin-bottom: 1.2rem; + overflow: visible; + border-radius: 14px; + height: 32px; + background-color: #25f; + border-right: 28px solid #11e; + border-left: 28px solid #11e; +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar span { + position: absolute; + top: -5px; + background-color: #000; + height: 40px; + overflow: visible; + padding-inline: 10px; + font-size: 36px; + line-height: 36px; + text-transform: uppercase; + color: #8bf; +} + +.lcars-text-bar::before { + content: ''; + background-color: #000; + display: block; + width: 10px; + height: 32px; + position: absolute; + top: 0; + left: 0; + overflow: hidden; +} + +.lcars-text-bar::after { + content: ''; + background-color: #000; + display: block; + width: 10px; + height: 32px; + position: absolute; + top: 0; + right: 0; + overflow: hidden; +} + +@media (max-width: 650px) { + + .lcars-text-bar { + border-radius: 10px; + height: 24px; + border-right-width: 20px; + border-left-width: 20px; + } + + .lcars-text-bar span { + position: absolute; + top: -3px; + height: 30px; + padding-inline: 5px; + font-size: 26px; + line-height: 26px; + } + + .lcars-text-bar::before, + .lcars-text-bar::after { + width: 5px; + height: 24px; + } + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + top: 5px; + transform: scale(80%); + } +} + +footer { + display: flex; + margin-top: clamp(50px, 6vw, 125px); + padding-block: 12px ; + background: linear-gradient(#25f 50%, #11e 50%); + border-radius: 0 20px 20px 0; + overflow: hidden; + position: relative; + z-index: 1; +} + +footer::before { + content: ''; + background-color: #000; + display: block; + width: 5px; + height: 100vh; + position: absolute; + top: 0; + left: 25%; + overflow: hidden; +} + +footer::after { + content: ''; + background-color: #000; + display: block; + width: 2px; + height: 100vh; + position: absolute; + top: 0; + left: -1px; + overflow: hidden; +} + +.footer-panel { + width: 12%; + max-width: 130px; + height: 100px; + margin: auto; + padding-top: 10px; + padding-left: .4rem; + background-color: #58f; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; +} + +.footer-inside { + flex: 1; + min-height: 180px; + background-color: #000; + border-radius: 0 20px 20px 0; + padding: 1.5rem 1rem; + z-index: 2; +} + +.footer-inside::before { + content: ''; + background-color: #25f; + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + top: 17px; + left: 1px; + overflow: hidden; +} + +.footer-inside::after { + content: ''; + background-color: #11e; + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + bottom: 12px; + left: 1px; + overflow: hidden; +} + +.footer-text { + display: flex; + flex-direction: column; + min-height: 146px; + align-items: center; + justify-content: center; + gap: .75rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.footer-text > * { + margin: 0; +} + +@media (max-width: 600px) { + + footer::before { + left: 40%; + } +} + +/* Grouped Media */ + +@media (max-width: 1240px) { + + .bar-1, + .bar-6 { + width: 320px; + } + + .panel-4 { + padding-top: 115px; + } + +} + +@media (max-width: 1100px) { + + .left-frame-top { + width: 180px; + min-width: 180px; + border-radius: 0 0 0 100px; + } + + .left-frame { + width: 180px; + min-width: 180px; + border-radius: 100px 0 0 0; + } + + .scroll-top a { + width: 180px; + } + + .bar-1, + .bar-6 { + width: 290px; + } + + .left-frame { + padding-top: 70px; + } + +} + +@media (max-width: 890px) { + + .left-frame-top, + .left-frame { + width: 150px; + min-width: 150px; + } + + .left-frame-top { + border-radius: 0 0 0 80px; + } + + .left-frame { + border-radius: 80px 0 0 0; + } + + .scroll-top a { + width: 150px; + padding: 10px 0 0 0; + text-align: center; + } + + .panel-1 a { + padding-top: 70px; + } + + .sutrebor { + margin: 4px 4px 19px 69px; + } + + .bar-1, + .bar-6 { + width: 180px; + } + + .bar-3, + .bar-8 { + width: 180px; + } + + blockquote { + margin-right: 0; + margin-left: 25px; + } + + .pics-right, + .pics-left { + float: none; + margin: 20px 0 20px 0; + } + + .pics-right img, + .pics-left img { + display: block; + margin: 0 auto; + } +} + +@media (max-width: 650px) { + + .left-frame-top, + .left-frame { + width: 110px; + min-width: 110px; + } + + .left-frame-top { + border-radius: 0 0 0 60px; + } + + .left-frame { + border-radius: 60px 0 0 0; + } + + .scroll-top a { + width: 110px; + height: 110px; + } + + .floor-text { + min-height: 10px; + padding-top: 0; + padding-bottom: 5px; + font-size: 1.2rem; + } + + .bar-panel { + height: 16px; + } + + .bar-1, + .bar-2, + .bar-3, + .bar-4, + .bar-5, + .bar-6, + .bar-7, + .bar-9, + .bar-10 { + height: 16px; + } + + .bar-1, + .bar-6 { + width: 130px; + } + + .bar-3, + .bar-8 { + width: 130px; + } + + .bar-5, + .bar-10 { + width: 25px; + } +} + +@media (max-width: 500px) { + + body { + padding: 0; + } + + .wrap { + padding-left: 0; + } + + .left-frame-top, + .left-frame { + width: 60px; + min-width: 60px; + font-size: .8rem; + } + + .left-frame-top { + border-radius: 0 0 0 26px; + } + + .left-frame { + border-radius: 26px 0 0 0; + padding-top: 50px; + } + + .scroll-top a { + width: 60px; + } + + .panel-1 a { + padding-top: 40px; + } + + .panel-2 a { + padding-top: 21px; + padding-bottom: 10px; + } + + .panel-6 { + padding-top: 150px; + } + + .hop { + display: none; + } + + .bar-panel { + height: 10px; + } + + .bar-1, + .bar-2, + .bar-3, + .bar-4, + .bar-5, + .bar-6, + .bar-7, + .bar-9, + .bar-10 { + height: 10px; + } + + .bar-3, + .bar-8 { + width: 80px; + } + + .bar-2, + .bar-7 { + width: 25px; + } + + .bar-8 { + height: 5px; + } + + #gap { + margin-top: 5px; + } + + .panel-4 { + padding-top: 65px; + } + + p.indent { + padding-left: 20px; + } + + blockquote { + margin: 25px 0 25px 20px; + } +} + +@media (max-width: 388px) { + + .bar-1, + .bar-6 { + width: 90px; + } +} \ No newline at end of file diff --git a/etc/experimental/janeway/assets/lcars-ultra-picard.css b/etc/experimental/janeway/assets/lcars-ultra-picard.css new file mode 100644 index 0000000..13f59ea --- /dev/null +++ b/etc/experimental/janeway/assets/lcars-ultra-picard.css @@ -0,0 +1,2650 @@ +@charset "utf-8"; + +/* + + CSS Document + LCARS Ultra - Picard Theme + Version 23-B + By Jim Robertus www.thelcars.com + Modified: 2024 Mar 7 + +*/ + +:root { + font-size: 1.5rem; + color-scheme: dark; + --sub-fonts: .8rem; + --dark-gray: #2f3749; + --medium-dark-gray: #52596e; /*6d748c*/ + --primary-gray: #6d748c; + --light-gray: #9ea5ba; + --ghost-gray: #d2d5df; /*dbdde6*/ + --starlight: #f3f4f7; + --cyan: #0ee; + --orange: #e7442a; + --light-orange: #ff6753; + --pale-orange: #ff977b; + --blue: #37a6d1; + --medium-dark-blue: #2a7193; + --dark-blue: #1c3c55; + --green: #808c6d; + --black-cherry: #8c6d7c; + --font-color: #828ba6; + --sidebar: 220px; + --bar-1: 120px; + --bar-6: 120px; + --bar-2: 120px; + --bar-7: 120px; + --bar-3: 40px; + --bar-8: 40px; + --bar: 22px; + --floatbar: 170px; +} + +@media (max-width: 1200px) { + + :root { + --sidebar: 190px; + } +} + +@media (max-width: 840px) { + + :root { + font-size: 1.3rem; + --sidebar: 160px; + --bar-1: 70px; + --bar-6: 70px; + --bar-2: 80px; + --bar-7: 80px; + } +} + +@media (max-width: 650px) { + + :root { + font-size: 1.2rem; + --sidebar: 90px; + --nav-font: .7rem; + --bar: 16px; + --floatbar: 50%; + } +} + +@media (max-width: 500px) { + :root { + --bar-1: 50px; + --bar-6: 50px; + --bar-2: 25px; + --bar-7: 25px; + --bar-3: 50px; + --bar-8: 50px; + --floatbar: 72%; + } +} + +*, *::after, *::before { + box-sizing: border-box; +} + +* { + margin: 0; + padding: 0; + font: inherit; +} + +img { + max-width: 100%; + height: auto; +} + +input, textarea, button, select { + font: inherit; +} + +/*html { + scroll-behavior: smooth; +}*/ + + +@font-face { + font-family: 'Antonio'; + font-weight: 400; + src: url('Antonio-Regular.woff2') format('woff2'), + url('Antonio-Regular.woff') format('woff'); +} + +@font-face { + font-family: 'Antonio'; + font-weight: 700; + src: url('Antonio-Bold.woff2') format('woff2'), + url('Antonio-Bold.woff') format('woff') +} + +body { + display: flex; + padding: 8px 10px; + background-color: #000; + font-family: 'Antonio', 'Arial Narrow', 'Avenir Next Condensed', sans-serif; + font-weight: 400; + line-height: 1.5; + color: var(--font-color) ; /* #828ba6 8e96af */ +} + +a { + color: var(--blue); + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: .2rem; +} + +a:hover { + filter: brightness(115%); + animation: none; +} + +a:active { + filter: brightness(80%); + outline: none; +} + +@keyframes blink { + 0% {opacity: 0} + 49%{opacity: 0} + 50% {opacity: 1} +} + +.wrap-everything { + display: flex; + width: 100%; + column-gap: 15px; +} + +#column-1 { + width: var(--sidebar); + transition: 800ms; + background-color: #000; + font-size: var(--sub-fonts); + font-weight: bold; +} + +#column-2 { + width: var(--sidebar); + text-align: right; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; + transition: 800ms; + z-index: 2; +} + +#column-2 a { + color: #000; + text-decoration: none; +} + +#column-3 { + flex: 1; +} + +#column-3-standard { + width: 100%; + max-width: 1440px; + margin-inline: auto; +} + +#column-3-standard-full-width { + width: 100%; +} + +.wrap { + display: flex; + margin-inline: auto; + overflow: hidden; +} + +.wrap-standard { + max-width: 1400px; +} + +.wrap-standard-full-screen { + max-width: 100%; +} + +@media (max-width: 1600px) { + + #column-1, + #column-2 { + margin-left: -235px; + } +} + +@media (max-width: 1300px) { + + #column-1, + #column-2 { + display: none; + } +} + +.lcars-frame { + display: flex; + height: 254px; + position: relative; +} + +.frame-col-1 { + width: 18px; + height: 254px; + background: var(--primary-gray); + border-radius: 16px 0 0 16px; + position: relative; +} + +.frame-col-1::before { + content: ''; + display: block; + width: 18px; + height: 174px; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + background-color: var(--primary-gray); + position: absolute; + top: 40px; + left: 0; +} + +.frame-col-1-cell-a { + width: 12px; + height: 57px; + background-color: var(--ghost-gray); + border-left: 4px solid #000; + border-bottom: 4px solid #000; + position: absolute; + top: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-b { + width: 12px; + height: 60px; + background-color: var(--ghost-gray); + border-left: 4px solid #000; + position: absolute; + top: 102px; + right: 0; + z-index: 2; +} + +.frame-col-1-cell-c { + width: 12px; + height: 57px; + background-color: var(--ghost-gray); + border-top: 4px solid #000; + border-left: 4px solid #000; + position: absolute; + bottom: 45px; + right: 0; + z-index: 2; +} + +.frame-col-1-blocks::before { + content: ''; + display: block; + width: 10px; + height: 3px; + background-color: #000; + position: absolute; + top: 54px; + left: 0; +} + +.frame-col-2 { + width:15px; + height: 254px; + background-color: var(--primary-gray); + position: relative; +} + +.frame-col-2::before { + content: ''; + display: block; + width: 15px; + height: 224px; + background-color: #000; + border-radius: 10px 0 0 10px; + position: absolute; + top: 15px; + left: 0; +} + +.frame-col-3 { + display: flex; + width: 187px; /* 164 */ + height: 254px; + padding-top: 35px; + align-items: center; + justify-content: center; + position: relative; +} + +.frame-col-3b { + width: 187px; + height: 254px; + padding-top: 20px; + text-align: left; + position: relative; + color: var(--primary-gray); +} + +.frame-col-4 { + width:15px; + height: 254px; + background-color: var(--primary-gray); + position: relative; +} + +.frame-col-4::before { + content: ''; + display: block; + width: 15px; + height: 224px; + background-color: #000; + border-radius: 0 10px 10px 0; + position: absolute; + top: 15px; + left: 0; +} + +.frame-col-5 { + width: 18px; + background-color: var(--primary-gray); + border-radius: 0 16px 16px 0; + padding-top: 40px; + position: relative; +} + +.frame-col-5::before { + content: ''; + display: block; + width: 18px; + height: 174px; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + background-color: var(--primary-gray); +} + +.frame-col-5-cell-a { + width: 12px; + height: 57px; + background-color: var(--ghost-gray); + border-bottom: 4px solid #000; + border-right: 4px solid #000; + position: absolute; + top: 45px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-b { + width: 12px; + height: 60px; + background-color: var(--ghost-gray); + border-right: 4px solid #000; + position: absolute; + top: 102px; + left: 0; + z-index: 2; +} + +.frame-col-5-cell-c { + width: 12px; + height: 57px; + background-color: var(--ghost-gray); + border-top: 4px solid #000; + border-right: 4px solid #000; + position: absolute; + bottom: 45px; + left: 0; + z-index: 2; +} + +.lcars-frame-after { + min-height: 57px; + text-align: right; + padding: 14px 10px 14px 15px; + background-color: var(--light-gray); + border-top: 10px solid #000; + text-transform: uppercase; + color: #000; +} + +.line { + height: 20px; + width: 3px; + background: linear-gradient(#000, var(--cyan), #000, #000); + transform: rotate(17deg); + +} + +.line:nth-child(even) { + width: 4px; +} + +.line:nth-child(1) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(2) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(3) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(4) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(5) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(6) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(7) { + animation: animateLine2 1s 0.8s infinite; +} + +/* 8 & 9 are middle lines*/ + +.line:nth-child(8) { + animation: animateLine4 1s 0.9s infinite; +} + +.line:nth-child(9) { + animation: animateLine4 1s 1s infinite; +} + +.line:nth-child(10) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(11) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(12) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(13) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(14) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(15) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(16) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(17) { + animation: animateLine6 1s 0.2s infinite; +} + +.line:nth-child(18) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(19) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(20) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(21) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(22) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(23) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(24) { + animation: animateLine4 1s 0.9s infinite; +} + +.line:nth-child(25) { + animation: animateLine4 1s 1s infinite; +} + +.line:nth-child(26) { + animation: animateLine2 1s 0.8s infinite; +} + +.line:nth-child(27) { + animation: animateLine2 1s 0.7s infinite; +} + +.line:nth-child(28) { + animation: animateLine2 1s 0.6s infinite; +} + +.line:nth-child(29) { + animation: animateLine3 1s 0.5s infinite; +} + +.line:nth-child(30) { + animation: animateLine3 1s 0.4s infinite; +} + +.line:nth-child(31) { + animation: animateLine5 1s 0.3s infinite; +} + +.line:nth-child(32) { + animation: animateLine6 1s 0.2s infinite; +} + +@keyframes animateLine2 { + 0% { + height: 180px; + } + 50% { + height: 90px; + } + 100% { + height: 180px; + } +} + +@keyframes animateLine3 { + 0% { + height: 120px; + } + 50% { + height: 60px; + } + 100% { + height: 120px; + } +} + +@keyframes animateLine4 { + 0% { + height: 230px; + } + 50% { + height: 115px; + } + 100% { + height: 230px; + } +} + +@keyframes animateLine5 { + 0% { + height: 60px; + } + 50% { + height: 30px; + } + 100% { + height: 60px; + } +} + +@keyframes animateLine6 { + 0% { + height: 30px; + } + 50% { + height: 15px; + } + 100% { + height: 30px; + } +} + +.panel-base { + margin-bottom: 6px; + height: 44px; + background-color: var(--primary-gray); + border-top: 4px solid #000; + border-bottom: 4px solid #000; + position: relative; +} + +.panel-base::after { + content: ''; + display: block; + width: 100px; + height: 10px; + position: absolute; + left: 60px; + top: 0; + background-color: #000; +} + +.panel-base-2nd-column { + margin-bottom: 6px; + height: 44px; + background-color: var(--medium-dark-gray); + border-top: 4px solid #000; + border-bottom: 4px solid #000; + box-shadow: 0 6px 0 #000; + position: relative; +} + +.panel-base-2nd-column::before { + content: ''; + display: block; + width: 100px; + height: 10px; + position: absolute; + left: 60px; + top: 0; + background-color: #000; +} + +.panel-20 { + padding-top: 15px; + padding-left: 15px; + height: 155px; + background-color: var(--primary-gray); + position: relative; + color: #000; +} + +.panel-20::before { + content: ''; + display: block; + width: 4px; + height: 155px; + position: absolute; + right: 40px; + top: 0; + background-color: #000; +} + +.panel-21 { + margin: 10px auto; + height: 160px; + padding-top: 15px; + padding-left: 15px; + border: 3px solid var(--medium-dark-gray); + color: var(--light-gray); +} + +.panel-23 { + display: flex; + width: var(--sidebar); + height: 254px; + padding-right: 10px; + padding-bottom: 10px; + background-color: var(--dark-gray); + align-items: flex-end; + justify-content: right; + position: relative; + color: var(--light-gray); +} + +.panel-23::before { + content: ''; + display: block; + width: var(--sidebar); + height: 127px; + background-color: var(--primary-gray); + border-bottom: 4px solid #000; + position: absolute; + top: 0; + left: 0; +} + +.panel-23::after { + content: ''; + display: block; + width: 20px; + height: 174px; + background-color: #000; + position: absolute; + top: 40px; + left: 0; +} + +.panel-23-after { + min-height: 57px; + text-align: right; + padding: 14px 10px 14px 15px; + background-color: var(--primary-gray); + border-top: 10px solid #000; + text-transform: uppercase; + color: #000; +} + +.elbow-continue-1 { + margin-top: 10px; + background-color: var(--light-gray); + padding-bottom: 20px; + position: relative; +} + +.elbow-continue-2 { + background-color: var(--primary-gray); + border-bottom: 4px solid #000; + padding-bottom: 20px; +} + +.elbow-continue-3 { + display: flex; + align-items: flex-end; + height: 200px; + background-color: var(--dark-gray); + padding-bottom: 15px; + padding-left: 15px; + border-bottom: 4px solid #000; + color: var(--light-gray); +} + +.elbow-close-1 { + margin-top: 10px; + background-color: var(--light-gray); + border-radius: 0 0 60px 0; + padding-bottom: 20px; + position: relative; +} + +.elbow-close-1::before { + content: ''; + display: block; + width: 20px; + height: 50px; + background-color: #000; + position: absolute; + top: 80px; + right: 20px; +} + +.elbow-close-2 { + width: 180px; + background-color: var(--primary-gray); + border-right: 4px solid #000; + border-bottom: 4px solid #000; + border-radius: 0 0 46px 0; + padding-bottom: 20px; +} + +.elbow-close-3 { + min-height: 200px; + width: 140px; + background-color: var(--dark-gray); + border-right: 4px solid #000; + border-bottom: 4px solid #000; + border-radius: 0 0 40px 0; + padding: 20px; + font-size: 1rem; +} + +@keyframes mover-1 { + 0% { transform: translateY(0); } + 100% { transform: translateY(-60px); } /* 125 -25 | -90 100*/ +} + +@keyframes mover-2 { + 0% { transform: translateY(0); } + 50% { transform: translateY(25px); } + 100% { transform: translateY(-15px); } +} + +.panel-24 { + display: flex; + width: var(--sidebar); + background-color: #000; + padding-top: 10px; + padding-bottom: 5px; + color: var(--light-gray); + gap: 5px; + position: relative; +} + +.panel-24::after { + content: ''; + display: block; + width: 80px; + height: 9px; + border-radius: 100%; + background-color: var(--starlight); + box-shadow: 3px 2px 8px #000; + position: absolute; + top: 212px; + left: 40px; + z-index: 1; +} + +.first-needle-static::after { + top: 244px; +} + +.first-needle::after { + top: 280px; + animation: mover-1 3s infinite alternate; +} + +.second-needle-static::after { + top: 174px; +} + +.second-needle::after { + top: 174px; + animation: mover-2 4s infinite alternate; +} + +.panel-24-col-a { + width: 110px; + border-top: 10px solid var(--primary-gray); + border-bottom: 12px solid var(--primary-gray); + background-color: #000; +} + +.panel-24-block-1 { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + height: 50px; + padding-top: 5px; + border-right: 22px solid var(--primary-gray); +} + +.panel-24-cube { + height: 20px; + border-right: 5px solid #000; +} + +.cc-1 { + background-color: var(--pale-orange); +} + +.cc-2 { + background-color: var(--blue); +} + +.cc-3 { + background-color: var(--medium-dark-blue); +} + +.cc-4 { + background-color: var(--light-gray); +} + +.cc-5 { + background-color: var(--primary-gray); +} + +.cc-6 { + background-color: var(--dark-gray); +} + +.panel-24-block-2 { + width: 22px; + height: 350px; + margin-left: 88px; + padding-top: 60px; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + background-color: var(--light-gray); +} + +.panel-24-block-3 { + width: 17px; + padding-top: 5px; + padding-right: 5px; + padding-bottom: 5px; + background-color: #000; +} + +.panel-24-block-4 { + width: 12px; + height: 220px; + padding-right: 5px; +} + +.block-4-color-a { + background-color: var(--blue); +} + +.block-4-color-b { + background-color: var(--orange); +} + +.panel-24-block-5 { + width: 22px; + height: 50px; + margin-left: 88px; + background-color: var(--primary-gray); +} + +.panel-24-col-b { + border-top: 10px solid var(--medium-dark-gray); + border-bottom: 12px solid var(--medium-dark-gray); + background-color: #000; + flex: 1; +} + +.panel-24-block-6 { + height: 50px; + text-align: right; + border-left: 12px solid var(--medium-dark-gray); + font-size: 1.2rem; + font-weight: normal; +} + +.gauge-wrap { + display: grid; + grid-template-columns: 1fr 1fr; + border-left: 12px solid var(--medium-dark-gray); + min-height: 400px; +} + +.gauge-1 { + height: 35px; + position: relative; +} + +.gauge-1::before { + content: ''; + display: block; + width: 46px; + height: 5px; + background-color: var(--medium-dark-gray); + position: absolute; + top:5px; + left: 0; +} + +.gauge-2 { + height: 35px; + text-align: right; + line-height: 1rem; +} + +.panel-25 { + display: grid; + grid-template-columns: 2fr 1fr; + gap: 8px; + height: 325px; + padding-bottom: 45px; + padding-left: 50px; + background-color: #000; + position: relative; + text-align: left; + font-size: .95rem; + color: var(--light-gray); +} + +.panel-25::after { + content: ''; + width: var(--sidebar); + height: 40px; + background-color: var(--dark-gray); + border-top: 4px solid black; + position: absolute; + left: 0; + bottom: 0; +} + +.panel-25::before { + content: ''; + width: 40px; + height: 296px; + background-color: var(--dark-gray); + position: absolute; + top: 0; + left: 0; +} + +.panel-25 div { + border-width: 3px; + border-style: solid; + text-align: center; + align-self: center; + padding-block: 4px; +} + +.panel-25 div:nth-child(odd) { + border-color: var(--blue); + padding-right: 10px; + text-align: right; + color: var(--blue); +} + +.panel-25 div:nth-child(even) { + border-color: var(--medium-dark-gray); + color: var(--primary-gray); +} + +.panel-25 div:nth-child(10) { + padding-inline: 10px; +} + +.panel-26 { + height: 155px; + margin-top: 10px; + margin-bottom: 10px; + padding-top: 15px; + padding-left: 15px; + background-color: var(--dark-gray); + position: relative; + text-align: left; + color: var(--light-gray); +} + +.panel-26::before { + content: ''; + width: 40px; + height: 155px; + border-left: 4px solid #000; + background-color: var(--primary-gray); + position: absolute; + top: 0; + right: 44px; +} + +.panel-26::after { + content: ''; + width: 45px; + height: 155px; + border-left: 4px solid #000; + background-color: var(--light-gray); + position: absolute; + top: 0; + right: 0; +} + +.scroll-top { + display: block; +} + +.scroll-top a { + display: none; + width: var(--sidebar); + height: 150px; + position: fixed; + bottom: 0; + text-decoration: none; + text-transform: uppercase; + text-align: right; + border-top: 5px solid #000; + border-bottom: 5px solid #000; + padding: 20px 10px 0 2px; + background-color: var(--orange); + font-size: .9rem; + font-weight: bold; + color: #000; + z-index: 1; +} + +.top-display { + display: flex; + width: 100%; + overflow: hidden; +} + +.top-display-left { + position: relative; + width: var(--sidebar); + background-color: var(--primary-gray); + overflow: visible; +} + +.chunk { + height: 31px; + background-color: var(--light-gray); + border-top: 2px solid #000; +} + +.panel-wrapper { + padding: 12px 0; + background-color: #000; +} + +.panel-1 { + padding: 15px; + text-align: right; + border: 3px solid var(--medium-dark-gray); + color: var(--light-gray); +} + +.top-display-right { + flex: 1; + position: relative; + overflow: hidden; + padding-left: 2.5vw; +} + +.top-display-content { + padding-top: 5px; +} + +.arch-bottom { + display: flex; + justify-content: flex-end; +} + +.top-arch-1 { + background-color: var(--dark-gray); + padding-top: 8px; + padding-right: 60px; + border-radius: 0 50px 0 0; + position: relative; +} + +.top-arch-1::before { + content: ''; + display: block; + width: 10%; + height: 200px; + border-top: 4px solid #000; + position: absolute; + bottom: 0; + right: 0; +} + +.top-arch-1::after { + content: ''; + display: block; + width: 4px; + height: 20px; + background-color: #000; + position: absolute; + top: 0; + left: 25%; + z-index: 1; +} + +.top-arch-2 { + display: flex; + overflow: hidden; + width: 100%; + background-color: var(--dark-gray); + padding-top: 8px; + border-top: 4px solid #000; + border-right: 4px solid #000; + border-radius: 0 50px 0 0; + align-items: flex-start; + position: relative; +} + +.arch-base { + width: 226px; + height: 40px; + background-color: var(--dark-gray); + border-top: 4px solid #000; + position: relative; +} + +.arch-base::before { + content: ''; + display: block; + width: 34px; + height: 16px; + background-color: #000; + position: absolute; + top: 10px; + left: 10px; +} + +.top-arch-content { + flex: 1; + min-height: 310px; + padding: 10px 2.5vw 0 0; + background-color: #000; + border-radius: 0 50px 0 0; +} + +.top-arch-content h1 { + text-align: left; + margin-top: 0; +} + +.sfc { + display: block; + margin: 20px auto 12px auto; + width: 188px; + height: auto; +} + +.top-arch-panel-1 { + width: 54px; + height: 200px; + background-color: var(--primary-gray); + border-top: 4px solid #000; + border-right: 4px solid #000; + align-self: flex-end; +} + +.top-arch-panel-2 { + width: 108px; + height: 200px; + padding-top: 145px; + padding-right: .75vw; + background-color: var(--dark-gray); + border-top: 4px solid #000; + align-self: flex-end; + text-align: right; +} + +.top-display-bottom { + display: flex; + position: relative; + overflow: hidden; + align-items: baseline; +} + +@media (max-width: 920px) { + + .top-arch-1 { + padding-right: 25px; + } + + .top-arch-panel-1 { + width: 20px; + } + + .top-arch-panel-2 { + width: 55px; + padding-right: 0; + text-align: center; + } + + .arch-base { + width: 104px; + } +} + +.top-display-bottom::before { + content: ''; + display: block; + width: 60px; + height: 48px; + background: linear-gradient(to top right, var(--primary-gray) 50%, #000 50%); + position: absolute; + left: var(--sidebar); + bottom: var(--bar); +} + +.top-display-bottom::after { + content: ''; + display: block; + width: 60px; + height: 48px; + background-color: #000; + border-radius: 0 0 0 48px; + position: absolute; + left: var(--sidebar); + bottom: var(--bar); +} + +.bar-elbow { + position: relative; + width: var(--sidebar); + height: 70px; + overflow: visible; +} + +.bar-elbow::after { + content: ''; + display: block; + width: var(--sidebar); + height: 70px; + position: absolute; + left: 0; + bottom: 0; + background-color: var(--primary-gray); + border-radius: 0 0 0 70px; +} + +.bar-runner { + display: flex; + height: var(--bar); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-8, +.bar-9, +.bar-10 { + height: var(--bar); +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-5, +.bar-6, +.bar-7, +.bar-8, +.bar-9, +.bar-10 { + transition: width 1s; +} + +.bar-1, +.bar-2, +.bar-3, +.bar-4, +.bar-6, +.bar-7, +.bar-8, +.bar-9 { + border-right: 8px solid #000; +} + +.bar-1 { + width: var(--bar-1); + background-color: var(--primary-gray); +} + +.bar-6 { + width: var(--bar-6); + background-color: var(--primary-gray); +} + +.bar-2 { + width: var(--bar-2); + background-color: var(--ghost-gray); +} + +.bar-3 { + width: var(--bar-3); + background-color: var(--primary-gray); +} + +.bar-4 { + flex: 1; + background-color: var(--light-gray); + padding-top: 12px; + position: relative; +} + +.bar-4::before { + content: ''; + display: block; + width: var(--floatbar); + height: 5px; + background-color: var(--primary-gray); + position: absolute; + bottom: 35px; + left: 0; +} + +.bar-4::after { + content: ''; + display: block; + width: var(--floatbar); + height: 10px; + background-color: black; + position: absolute; + left: 0; + bottom: 0; +} + +.bar-5, +.bar-10 { + width: 55px; + background-color: var(--medium-dark-gray); +} + +.bar-7 { + width: var(--bar-7); + background-color: var(--ghost-gray); +} + +.bar-8 { + width: var(--bar-8); + background-color: var(--primary-gray); +} + +.bar-9 { + flex: 1; + background-color: var(--primary-gray); + position: relative; +} + +.bar-9::before { + content: ''; + display: block; + width: var(--floatbar); + height: 10px; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.bar-9::after { + content: ''; + display: block; + width: var(--floatbar); + height: 5px; + background-color: var(--light-gray); + position: absolute; + top: 35px; + left: 0; +} + +.corner-bg { + width: 150px; + height: 50px; + background: linear-gradient(to bottom right, var(--primary-gray) 50%, #000 50%); +} + +.corner { + width: 150px; + height: 50px; + background-color: #000; + border-radius: 40px 0 0 0; +} + +.left-frame { + width: var(--sidebar); + background-color: var(--primary-gray); + padding-top: 80px; + border-radius: 70px 0 0 0; + text-align: right; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; +} + +.left-frame a { + text-decoration: none; + color: #000; +} + +.panel-2 { + padding-top: 15px; + padding-right: 10px; +} + +.right-frame-top { + flex: 1; + position: relative; +} + +.right-frame-top::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to top right, #78f 50%, #000 50%); + position: absolute; + left: 0; + bottom: 22px; + z-index: -1; +} + +.right-frame-top::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: #000; + border-radius: 0 0 0 56px; + position: absolute; + left: 0; + bottom: 22px; + z-index: -1; +} + +@media (max-width: 1100px) { + + .right-frame-top::after { + border-radius: 0 0 0 40px; + } +} + +@media (max-width: 650px) { + + .right-frame-top::before { + bottom: 16px; + } + + .right-frame-top::after { + border-radius: 0 0 0 30px; + bottom: 16px; + } +} + +@media (max-width: 500px) { + + .right-frame-top::before { + bottom: 10px; + } + + .right-frame-top::after { + border-radius: 0 0 0 16px; + bottom: 10px; + } +} + +.lcars-heading { + padding-bottom: 2px; + text-align: center; + text-transform: uppercase; + line-height: 1.1; + font-size: clamp(1rem, 0.8696rem + 0.5217vw, 1.6rem); + color: var(--blue); +} + +.lcars-heading a { + text-decoration: none; +} + +.lcars-access { + text-align: center; + text-transform: uppercase; + color: var(--dark-blue); +} + +#primary-nav { + background-color: #000; + overflow: hidden; +} + +#primary-nav a { + display: block; + margin-bottom: 10px; + background-color: #000; + border-width: 3px; + border-style: solid; + border-color: var(--orange); + min-height: 20px; + font-weight: bold; + text-align: right; + line-height: 1.1; + padding: 10px 10px 11px 5px; + text-decoration: none; + font-size: var(--nav-font); + color: var(--orange); +} + +#primary-nav a:hover { + filter: none; + border-color: var(--pale-orange); + color: var(--pale-orange); +} + +.spacer { + display: flex; + max-width: 100%; + height: 10px; + position: relative; +} + +.space-sidebar { + width: var(--sidebar); +} + +.space-1 { + width: var(--bar-1); +} + +.space-2 { + width: var(--bar-2); +} + +.space-3 { + width: var(--bar-3); +} + +.space-4 { + flex: 1; + position: relative; +} + +.space-4::before { + content: ''; + display: block; + width: 25px; + height: 20px; + background-color: var(--ghost-gray); + position: absolute; + bottom: -5px; + left: 0; + z-index: 1; + transition: all 1s; +} + +.space-4::after { + content: ''; + display: block; + width: 30px; + height: 20px; + background-color: var(--medium-dark-gray); + border-right: 5px solid black; + box-shadow: 25px 0 0 var(--dark-gray); + position: absolute; + bottom: -5px; + left: 30px; + z-index: 1; + transition: all 1s; +} + +#secondary-nav { + padding-top: 2px; + background-color: #000; + overflow: hidden; +} + +#secondary-nav a { + display: block; + margin: 8px auto; + text-decoration: none; + text-align: right; + border-left: 15px solid var(--primary-gray); + padding: 10px 10px 10px 15px; + background-color: var(--light-gray); + text-transform: uppercase; + color: #000; + position: relative; +} + +#secondary-nav a::before { + content: ''; + display: block; + width: 10px; + height: 150px; + background-color: #000; + position: absolute; + top: 0; + left: 0; +} + +#secondary-nav a:nth-child(1) { + margin-top: 0; +} + +#secondary-nav a:nth-child(even) { + border-left-color: var(--medium-dark-gray); +} + +a.bc-blue { + background-color: var(--blue) !important; +} + +a.bc-orange { + background-color: var(--orange) !important; +} + +a.bc-ghost-gray { + background-color: var(--ghost-gray) !important; +} + +a.bc-pale-orange { + background-color: var(--pale-orange) !important; +} + +#secondary-nav a:hover { + border-left-color: var(--blue); +} + +@media (max-width: 800px) { + + #secondary-nav a { + border-left-width: 5px; + } + #secondary-nav a::before { + width: 5px; + } +} + +@media (max-width: 650px) { + + #secondary-nav a { + min-height: 40px; + padding: 8px 8px 8px 15px; + } +} + +.panel-3, +.panel-4, +.panel-5, +.panel-6, +.panel-7, +.panel-8 { + padding-right: 10px; + border-bottom: 5px solid #000; +} + +.panel-3 { + Padding-top: 15px; + padding-bottom: 15px; +} + +.panel-4 { + height: 99px; + Padding-top: 50px; + padding-bottom: 15px; + background-color: var(--dark-gray); + position: relative; + color: var(--light-gray); +} + +.panel-4::after { + content: ''; + display: block; + width: 45px; + height: 328px; + position: absolute; + left: 0; + top: 0; + background-color: var(--light-gray); + border-right: 5px solid #000; + border-bottom: 5px solid #000; +} + +.panel-5 { + height: 229px; + padding-top: 180px; + padding-bottom: 15px; + background-color: var(--dark-gray); + color: var(--light-gray); +} + +.panel-6 { + padding: 31px 10px 31px 0; + background-color: var(--primary-gray); +} + +.panel-7 { + padding: 15px 10px 75px 0; + background-color: var(--light-gray); +} + +.panel-8 { + height: 295px; + border-bottom: 5px solid #000; + background-color: var(--dark-gray); + Padding-top: 15px; + padding-right: 10px; + color: var(--light-gray); +} + +.right-frame { + flex: 1; + position: relative; +} + +.right-frame::before { + content: ''; + display: block; + width: 60px; + height: 60px; + background: linear-gradient(to bottom right, var(--primary-gray) 50%, #000 50%); + position: absolute; + left: 0; + top: 22px; + z-index: -1; +} + +.right-frame::after { + content: ''; + display: block; + width: 60px; + height: 60px; + background-color: #000; + border-radius: 48px 0 0 0; + position: absolute; + left: 0; + top: 22px; + z-index: -1; +} + +main { + padding-top: 40px; + padding-right: 10px; + padding-bottom: 25px; + padding-left: clamp(20px, 3vw, 50px); +} + +main > *:first-child, +article > *:first-child { + margin-top: 0; +} + +.flexbox { + display: flex; + gap: 1.2rem; + flex-wrap: wrap; +} + +.col { + flex: 1 1 360px; +} + +.col > *:first-child { + margin-top: 0; +} + +h1, h2, h3 { + margin-top: 1.15rem; + margin-bottom: 1rem; + font-weight: normal; + line-height: 1.2; + text-transform: uppercase; +} + +h1 { + font-size: clamp(1.65rem, 1.1826rem + 1.8696vw, 3.8rem); + text-align: right; + color: var(--pale-orange); +} + +h2 { + font-size: clamp(1.4rem, 1.2696rem + 0.5217vw, 2rem); + color: var(--pale-orange); +} + +h3 { + font-size: clamp(1.1rem, 1.213rem + 0.3478vw, 1.2rem); + color: var(--medium-dark-blue); +} + +p { + margin-block: 1rem; +} + +.caption { + margin-top: .5rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.indent { + padding-left: 40px; +} + +.postmeta { + margin: .25rem 0 1.25rem 0; + text-align: right; + font-size: clamp(1.2rem, 0.88rem + 1.28vw, 1.6rem); + line-height: 1.2; + text-transform: uppercase; +} + +article h1 { + margin-bottom: 0; +} + +code { + font-family: monospace; + font-size: .9rem; + color: var(--green); +} + +hr { + margin: 1rem 0; + height: 6px; + border: none; + background-color: var(--primary-gray); + border-radius: 3px; +} + +blockquote { + margin: 30px 40px; + border-left: 4px solid var(--primary-gray); + padding-left: 20px; +} + +.dark-gray { + color: var(--dark-gray); +} + +.medium-dark-gray { + color: var(--medium-dark-gray); +} + +.primary-gray { + color: var(--primary-gray); +} + +.light-gray { + color: var(--light-gray); +} + +.ghost-gray { + color: var(--ghost-gray); +} + +.starlight { + color: var(--starlight); +} + +.cyan { + color: var(--cyan); +} + +.orange { + color: var(--orange); +} + +.light-orange { + color: var(--light-orange); +} + +.pale-orange { + color: var(--pale-orange); +} + +.blue { + color: var(--blue); +} + +.medium-dark-blue { + color: var(--medium-dark-blue); +} + +.dark-blue { + color: var(--dark-blue); +} + +.green { + color: var(--green); +} + +.black-cherry { + color: var(--black-cherry); +} + +.flush { + margin-top: -1rem; +} + +.nomar { + margin: 0 !important; +} + +.go-center { + text-align: center !important; +} + +.go-right { + text-align: right !important; +} + +.go-left { + text-align: left !important; +} + +.go-big { + font-size: clamp(1.14rem, 0.94rem + 0.81vw, 1.4rem); +} + +.uppercase { + text-transform: uppercase; +} + +.strike { + text-decoration: line-through; + text-decoration-thickness: .15rem; +} + +.now { + white-space: nowrap; +} + +.big-sky { + margin-top: 4rem; +} + +strong { + font-weight: bold; + color: var(--light-orange); +} + +.blink { + animation: blink 2s infinite; + animation-delay: 1s; +} + +.blink-slow, +.blink-slower /* blink-slower is for backwards compatibility */ { + animation: blink 3s infinite; + animation-delay: 1s; +} + +.blink-fast, +.blink-faster /* blink-faster is for backwards compatibility */ { + animation: blink 1s infinite; + animation-delay: 1s; +} + +/* Images */ + +.pics-right { + float: right; + margin: 10px 0 20px 20px; +} + +.pics-left { + float: left; + margin: 10px 20px 20px 0; +} + +.pics { + display: block; + margin: 1.5rem auto 0 auto; +} + +.border { + padding: 10px; + border: 2px solid var(--primary-gray); +} + +.lcars-list { + margin-top: 1rem; + margin-left: 2rem; + list-style: none; +} + +.lcars-list li { + position: relative; + padding-bottom: .4rem; + padding-left: 2rem; +} + +.lcars-list li::before { + content: ''; + display: block; + width: 30px; + height: 20px; + border-radius: 50%; + background-color: var(--primary-gray); + position: absolute; + top: 10px; + left: 0; +} + +li.bullet-dark-gray::before { + background-color: var(--dark-gray); +} + +li.bullet-medium-dark-gray::before { + background-color: var(--medium-dark-gray); +} + +li.bullet-light-gray::before { + background-color: var(--light-gray); +} + +li.bullet-ghost-gray::before { + background-color: var(--ghost-gray); +} + +li.bullet-starlight::before { + background-color: var(--starlight); +} + +li.bullet-cyan::before { + background-color: var(--cyan); +} + +li.bullet-orange::before { + background-color: var(--orange); +} + +li.bullet-light-orange::before { + background-color: var(--light-orange); +} + +li.bullet-pale-orange::before { + background-color: var(--pale-orange); +} + +li.bullet-blue::before { + background-color: var(--blue); +} + +li.bullet-medium-dark-blue::before { + background-color: var(--medium-dark-blue); +} + +li.bullet-dark-blue::before { + background-color: var(--dark-blue); +} + +li.bullet-green::before { + background-color: var(--green); +} + +li.bullet-black-cherry::before { + background-color: var(--black-cherry); +} + +.buttons { + margin-block: 1.5rem; + display: flex; + flex-wrap: wrap; + gap: 15px; +} + +.jc-space-between { + justify-content: space-between; +} + +.jc-center { + justify-content: center; +} + +.jc-flex-end { + justify-content: flex-end; +} + +.jc-space-around { + justify-content: space-around; +} + +.jc-space-evenly { + justify-content: space-evenly; +} + +.buttons a { + display: flex; + justify-content: flex-end; + align-items: center; + min-height: 48px; + position: relative; + width: 210px; + padding-top: 3px; + padding-right: 10px; + padding-bottom: 3px; + background-color: var(--primary-gray); + border-left: 15px solid var(--light-gray); + text-align: right; + line-height: normal; + text-decoration: none; + font-size: var(--sub-fonts); + font-weight: bold; + text-transform: uppercase; + color: #000; + -webkit-touch-callout: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.buttons a:nth-child(odd) { + border-color: var(--medium-dark-gray); +} + +.buttons a:nth-child(even) { + border-color: var(--light-gray); +} + +.buttons a::before { + content: ''; + display: block; + width: 10px; + height: 100%; + background-color: black; + position: absolute; + top: 0; + left: 0; +} + +.buttons a:hover { + border-left-color: var(--blue); +} + +@media (max-width: 650px) { + + .buttons a { + font-size: .9rem; + } +} + +.lcars-bar { + margin: 40px auto; + height: 22px; + background-color: var(--medium-dark-gray); + border-right: 20px solid var(--primary-gray); + border-left: 20px solid var(--primary-gray); + border-radius: 100vmax; + padding-inline: 5px; + position: relative; +} + +.lcars-bar::before { + content: ''; + display: block; + height: 22px; + width: 100%; + border-right: 8px solid #000; + border-left: 8px solid #000; + position: absolute; + top: 0; + left: 0; + z-index: 1; +} + +.lcars-text-bar { + display: flex; + position: relative; + margin-top: 1.5rem; + margin-bottom: 1.2rem; + overflow: visible; + border-radius: 14px; + height: 32px; + background-color: var(--primary-gray); + border-right: 28px solid var(--primary-gray); + border-left: 28px solid var(--orange); +} + +.lcars-text-bar::after { + content: ''; + display: block; + width: 100%; + height: 19px; + background-color: var(--medium-dark-gray); + border-bottom: 5px solid #000; + position: absolute; + top: 0; + left: 0; +} + +.lcars-text-bar::before { + content: ''; + display: block; + height: 32px; + width: 100%; + border-right: 10px solid #000; + border-left: 10px solid #000; + position: absolute; + z-index: 1; +} + +.the-end { + justify-content: flex-end; +} + +.lcars-text-bar span { + position: absolute; + top: -5px; + background-color: #000; + height: 40px; + overflow: visible; + padding-inline: 10px; + font-size: 36px; /* 1.4rem */ + line-height: 36px; + text-transform: uppercase; + color: var(--light-gray); + z-index: 1; +} + +@media (max-width: 840px) { + + .lcars-list { + margin-left: .5rem; + } + + .lcars-list li::before { + top: 7px; + transform: scale(80%); + } + + .lcars-text-bar { + border-radius: 10px; + height: 24px; + border-right-width: 20px; + border-left-width: 20px; + } + + .lcars-text-bar span { + position: absolute; + top: -3px; + height: 30px; + padding-inline: 5px; + font-size: 26px; + line-height: 26px; + } + .lcars-text-bar::after { + height: 14px; + border-bottom: 4px solid #000; + } +} + +footer { + display: flex; + margin-top: clamp(50px, 6vw, 125px); + padding-block: 12px ; + background: linear-gradient(var(--medium-dark-gray) 50%, var(--dark-gray) 50%); + border-radius: 0 20px 20px 0; + overflow: hidden; + position: relative; + z-index: 1; +} + +footer::before { + content: ''; + background-color: #000; + display: block; + width: 5px; + height: 100vh; + position: absolute; + top: 0; + left: 25%; + overflow: hidden; +} + +footer::after { + content: ''; + background-color: #000; + display: block; + width: 2px; + height: 100vh; + position: absolute; + top: 0; + left: -1px; + overflow: hidden; +} + +.footer-panel { + width: 12%; + max-width: 130px; + height: 100px; + margin: auto; + padding-top: 10px; + padding-left: .4rem; + background-color: var(--light-gray); + border-top: 5px solid #000; + border-bottom: 5px solid #000; + font-size: var(--sub-fonts); + font-weight: bold; + color: #000; +} + +.footer-inside { + flex: 1; + min-height: 180px; + background-color: #000; + border-radius: 0 20px 20px 0; + padding: 1.5rem 1rem; + z-index: 2; +} + +.footer-inside::before { + content: ''; + background-color: var(--primary-gray); + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + top: 17px; + left: 1px; + overflow: hidden; +} + +.footer-inside::after { + content: ''; + background-color: var(--dark-gray); + display: block; + width: 15%; + min-width: 60px; + height: 10px; + position: absolute; + bottom: 12px; + left: 1px; + overflow: hidden; +} + +.footer-text { + display: flex; + flex-direction: column; + min-height: 146px; + align-items: center; + justify-content: center; + gap: .75rem; + text-align: center; + font-size: var(--sub-fonts); +} + +.footer-text > * { + margin: 0; +} + +@media (max-width: 600px) { + + footer::before { + left: 40%; + } +} + +@media (max-width: 890px) { + + .scroll-top a { + padding: 10px 0 0 0; + text-align: center; + } + + main { + padding-top: 30px; + padding-right: 5px; + } + + .sutrebor { + margin: 4px 4px 19px 69px; + } + + blockquote { + margin-right: 0; + margin-left: 25px; + } + + .pics-right, + .pics-left { + float: none; + margin: 20px 0 20px 0; + } + + .pics-right img, + .pics-left img { + display: block; + margin: 0 auto; + } +} + +@media (max-width: 650px) { + + .left-frame { + border-radius: 40px 0 0 0; + } + + .bar-elbow { + height: 40px; + } + + .bar-elbow::after { + height: 40px; + border-radius: 0 0 0 40px; + } + + .top-arch-content { + min-height: 150px; + } + + .top-arch-panel-1, + .top-arch-panel-2, + .top-arch-1::before { + height: 100px; + } + + .top-arch-panel-2 { + padding-top: 60px; + font-size: .8rem; + } + + .top-display-bottom::after { + border-radius: 0 0 0 26px; + } + + .right-frame::before { + top: 16px; + } + + .right-frame::after { + border-radius: 26px 0 0 0; + top: 16px; + } + + .scroll-top a { + height: 110px; + } + + .bar-5, + .bar-10 { + width: 25px; + } + + .bar-4 { + padding-top: 6px; + } + + .bar-4::before { + height: 5px; + bottom: 26px; + } + + .bar-9::after { + height: 5px; + top: 26px; + } + + .space-4::before { + width: 20px; + height: 14px; + bottom: -2px; + } + + .space-4::after { + width: 25px; + height: 14px; + bottom: -2px; + left: 25px; + box-shadow: 20px 0 0 var(--dark-gray); + } + + .panel-4::after { + width: 20px; + } + + .lcars-list li::before { + top: 5px; + } +} + +@media (max-width: 500px) { + + body { + padding-left: 3px; + } + + #primary-nav a { + padding: 7px 3px 8px 3px; + border-width: 2px; + margin-bottom: 7px; + } + + .chunk { + height: 10px; + } + + .lcars-access { + display: none; + } + + .panel-wrapper { + padding: 7px 0; + } + + .panel-1 { + padding: 3px 5px 3px 3px; + font-size: var(--sub-fonts); + border-width: 2px; + } + + .left-frame { + padding-top: 50px; + font-size: .8rem; + } + + .panel-2 { + padding-bottom: 15px; + border-bottom: 5px solid #000; + background-color: #78f; + } + + .panel-6 { + padding-top: 150px; + } + + .hop { + display: none; + } + + .sfc { + width: 160px; + margin-top: 5px; + margin-bottom: 2px; + } + + .top-arch-1 { + padding-right: 15px; + } + + .top-arch-panel-2 { + width: 35px; + font-size: .7rem; + } + + .arch-base { + width: 74px; + height: 24px; + } + + .arch-base::before { + width: 14px; + height: 8px; + top: 6px; + left: 6px; + } + + p.indent { + padding-left: 20px; + } + + blockquote { + margin: 25px 0 25px 20px; + } +} \ No newline at end of file diff --git a/etc/experimental/janeway/assets/lcars.js b/etc/experimental/janeway/assets/lcars.js new file mode 100644 index 0000000..9570c83 --- /dev/null +++ b/etc/experimental/janeway/assets/lcars.js @@ -0,0 +1,19 @@ +document.addEventListener("touchstart", function() {},false); + +$(window).scroll(function() { + var height = $(window).scrollTop(); + if (height > 100) { + $('.scroll-top a').fadeIn(); + } else { + $('.scroll-top a').fadeOut(); + } +}); + +$(document).ready(function() { + $("#scroll-top").click(function(event) { + event.preventDefault(); + $("html, body").animate({ scrollTop: 0 }, "slow"); + return false; + }); + +}); \ No newline at end of file diff --git a/etc/experimental/janeway/assets/sfcmd.png b/etc/experimental/janeway/assets/sfcmd.png new file mode 100644 index 0000000..8f38791 Binary files /dev/null and b/etc/experimental/janeway/assets/sfcmd.png differ diff --git a/etc/experimental/janeway/janeway_lcars.html b/etc/experimental/janeway/janeway_lcars.html new file mode 100644 index 0000000..8f7af81 --- /dev/null +++ b/etc/experimental/janeway/janeway_lcars.html @@ -0,0 +1,397 @@ + + + + + Page Title + + + + + + + + + +
+
+ +
+ +
02-262000
+
+
+ +
+
+
+
+
101
7109
1966
36
880
11.03
1954
03
6.08
241
309
7.08
1935
12.20
53
1961
2.16
+
+ +
102
8102
1987
044
0051
1968
704
10.31
1984
1954
764
1940
9.9
1972
815
4.12
2023
103
714
1993
0222
4.4
1969
2450
91
56
21
716
801
417
602
5618
238
1443
104
6104
1995
3.22
1931
0.0
0000
1701
1984
218
908
10
85
1888
27
2879
213
105
08
2001
713
079
1977
LV
426
105
10
1642
1979
402
795
361
0852
984
106
31
2017
429
65
871
24
541
656
M
113
12.6
27
05
85
12.25
7884
107
5
2022
784
3304
42
733
1224
5801
23
1015
84
36
029
24
318
12.24
108
23
174
91
947
28
527
04
0469
2200
88
1985
540
3121
308
9571
404
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
04-ELEMENTS
+
05-SESSIONS
+
06-LOG
+
03-111968
+
07-081940
+
08-47148
+
09-081966
+
+
+
10-31
+
+
+
+
+
+
+
+
+
+
+
+ + + +

...

+ + + + + + + + + +
Data
Awaiting feed selection
+ + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/etc/experimental/tantor/Makefile b/etc/experimental/tantor/Makefile new file mode 100644 index 0000000..918a1ef --- /dev/null +++ b/etc/experimental/tantor/Makefile @@ -0,0 +1,29 @@ +OS=linux +ARCH=amd64 +BINARY_NAME=tantor +PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled +SAMPLEPROVISIONINGFILE=sample.yaml + + +build: libs fmt + GOOS=${OS} GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + strip ${BINARY_NAME} + +fmt: + go fmt ./... + +libs: + go get -u + go mod tidy -v + +vet: + go vet -composites=false ./... + +run: build + ./${BINARY_NAME} ${SAMPLEPROVISIONINGFILE} + +clean: + go clean + rm ${BINARY_NAME} diff --git a/etc/experimental/tantor/actions/Worklist.go b/etc/experimental/tantor/actions/Worklist.go new file mode 100644 index 0000000..9820f6e --- /dev/null +++ b/etc/experimental/tantor/actions/Worklist.go @@ -0,0 +1,84 @@ +package actions + +import ( + "fmt" + "tantor/provisioningfile" +) + +var eid string + +func RunWorklist(ws []string) { + for j, v := range ws { + fmt.Printf("Running item %v : %v\n", j, v) + + switch { + case v == "collectsysinfo": + h, _ := CollectSystemInfo() + provisioningfile.ProvisioningData.Element.Host = h + successmessage("Host identified") + case v == "collectuefi": + f, err := CollectUEFIEventLogLocation() + if err == nil { + provisioningfile.ProvisioningData.Element.UEFI.Eventlog = f + successmessage(f) + } else { + errormessage(err) + } + case v == "collectuefi": + f, err := CollectIMALogLocation() + if err == nil { + provisioningfile.ProvisioningData.Element.IMA.ASCIILog = f + successmessage(f) + } else { + errormessage(err) + } + case v == "collectima": + f, err := CollectIMALogLocation() + if err == nil { + provisioningfile.ProvisioningData.Element.IMA.ASCIILog = f + successmessage(f) + } else { + errormessage(err) + } + case v == "tpmclear": + _, err := TPMClear() + if err == nil { + successmessage("TPM cleared") + } else { + errormessage(err) + } + case v == "tpmprovision": + _, err := TPMProvision() + if err == nil { + successmessage("TPM Provisioned") + } else { + errormessage(err) + } + case v == "createevs": + _, err := CreateEVS(eid) + if err == nil { + successmessage("EVS Created") + } else { + errormessage(err) + } + case v == "createelement": + e, err := CreateElement() + eid = e + if err == nil { + successmessage("Element Created " + eid) + } else { + errormessage(err) + } + default: + fmt.Println("Error: unknown work request") + } + } +} + +func successmessage(msg string) { + fmt.Printf("* success: %v\n", msg) +} + +func errormessage(e error) { + fmt.Printf("X error %w\n", e.Error()) +} diff --git a/etc/experimental/tantor/actions/collectevs.go b/etc/experimental/tantor/actions/collectevs.go new file mode 100644 index 0000000..495d6e7 --- /dev/null +++ b/etc/experimental/tantor/actions/collectevs.go @@ -0,0 +1,40 @@ +package actions + +import ( + "fmt" + + "tantor/janeapi" + "tantor/provisioningfile" +) + +type postAttestReturn struct { + Itemid string `json:"itemid"` + Error string `json:"error"` +} + +func CreateEVS(eid string) (string, error) { + + s, _ := janeapi.OpenSession("Tantor: Creating EVS for " + eid) + + for _, v := range provisioningfile.ProvisioningData.Evs { + fmt.Printf("A>>> evs %v\n", v) + + a := janeapi.AttestStr{ + EID: eid, + EPN: "tarzan", + PID: v, + SID: s, + } + + r, err := janeapi.Attest(a) + fmt.Printf("<< /dev/null + +#Print stuff +echo Session was $SESSION with claim obtained is $CLAIMID +curl -s -X GET http://192.168.0.40:8520/session/$SESSION | jq . \ No newline at end of file diff --git a/etc/scripts/shellscriptideas/att_stress.sh b/etc/scripts/shellscriptideas/att_stress.sh new file mode 100755 index 0000000..0dacda2 --- /dev/null +++ b/etc/scripts/shellscriptideas/att_stress.sh @@ -0,0 +1,194 @@ +#!/bin/sh -x + +ELEMENT=0655caed-65ce-4755-a951-9f37e81904e2 +POLICY1=std::intent::sys::info +POLICY2=std::intent::sha256::crtm::pcr0 +POLICY3=std::intent::linux::ima::asciilog + + + +EN="$(curl -s -X GET http://192.168.0.40:8520/element/$ELEMENT | jq -r .name)" +PN="$(curl -s -X GET http://192.168.0.40:8520/intent/$POLICY | jq -r .name)" + + +echo Applying $PN to $EN + + +#open session +SESSION="$(curl -s -X POST http://192.168.0.40:8520/session -H "Content-Type: application/json" --data '{"message":"test from curl"}' | jq -r .itemid)" + +#attest element +echo $ELEMENTID + +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID1="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY1'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID2="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +CLAIMID3="$(curl -s -X POST http://192.168.0.40:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" + +#close session +curl -s -X DELETE http://192.168.0.40:8520/session/$SESSION > /dev/null + +#Print stuff +echo Session was $SESSION with claim obtained is $CLAIMID +curl -s -X GET http://192.168.0.40:8520/session/$SESSION | jq . \ No newline at end of file diff --git a/etc/scripts/tpmtest/go.mod b/etc/scripts/tpmtest/go.mod new file mode 100644 index 0000000..06f368b --- /dev/null +++ b/etc/scripts/tpmtest/go.mod @@ -0,0 +1,7 @@ +module tpmtest + +go 1.23.2 + +require github.com/google/go-tpm v0.9.2 + +require golang.org/x/sys v0.28.0 // indirect diff --git a/etc/scripts/tpmtest/go.sum b/etc/scripts/tpmtest/go.sum new file mode 100644 index 0000000..2257fc6 --- /dev/null +++ b/etc/scripts/tpmtest/go.sum @@ -0,0 +1,6 @@ +github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM= +github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm v0.9.2 h1:Gh8CMnMm06b09DmcsuY9fI3oF69188lGXCpiT/a05T4= +github.com/google/go-tpm v0.9.2/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/etc/scripts/tpmtest/scratch b/etc/scripts/tpmtest/scratch new file mode 100644 index 0000000..76cbee8 --- /dev/null +++ b/etc/scripts/tpmtest/scratch @@ -0,0 +1,131 @@ + +var RSAAKTemplate = tpm2.TPMTPublic{ + Type: tpm2.TPMAlgRSA, + NameAlg: tpm2.TPMAlgRSASSA, + ObjectAttributes: tpm2.TPMAObject{ + FixedTPM: true, + + + RSASRKTemplate = TPMTPublic{ + Type: TPMAlgRSA, + NameAlg: TPMAlgSHA256, + ObjectAttributes: TPMAObject{ + FixedTPM: true, + STClear: false, + FixedParent: true, + SensitiveDataOrigin: true, + UserWithAuth: true, + AdminWithPolicy: false, + NoDA: true, + EncryptedDuplication: false, + Restricted: true, + Decrypt: true, + SignEncrypt: false, + }, + Parameters: NewTPMUPublicParms( + TPMAlgRSA, + &TPMSRSAParms{ + Symmetric: TPMTSymDefObject{ + Algorithm: TPMAlgAES, + KeyBits: NewTPMUSymKeyBits( + TPMAlgAES, + TPMKeyBits(128), + ), + Mode: NewTPMUSymMode( + TPMAlgAES, + TPMAlgCFB, + ), + }, + KeyBits: 2048, + }, + ), + Unique: NewTPMUPublicID( + TPMAlgRSA, + &TPM2BPublicKeyRSA{ + Buffer: make([]byte, 256), + }, + ), + } + + + + + + + + ektmpl := tpm2.CreatePrimary{ + PrimaryHandle: tpm2.TPMRHEndorsement, + InPublic: tpm2.New2B(tpm2.RSAEKTemplate), + } + ersp,err := ektmpl.Execute(tpm) + fmt.Printf("Create Primary response %v, %w\n",ersp,err) + fmt.Printf(" Object handle is %x\n",ersp.ObjectHandle) + fmt.Printf(" Name %s\n", base64.StdEncoding.EncodeToString(ersp.Name.Buffer)) + + fmt.Println("\nAttempting evict control") + + vrsp, err := tpm2.EvictControl{ + Auth: tpm2.TPMRHOwner, + ObjectHandle: &tpm2.NamedHandle{ + Handle: ersp.ObjectHandle, + Name: ersp.Name, + }, + PersistentHandle: tpm2.TPMHandle(0x81000002), + }.Execute(tpm) + + fmt.Printf("Evict control response %v, %w\n",vrsp,err) + + + + fmt.Println("\nAttempting to create the an attestation key, load and store it") + + rsaTemplate := tpm2.TPMTPublic{ + Type: tpm2.TPMAlgRSA, + NameAlg: tpm2.TPMAlgSHA256, + ObjectAttributes: tpm2.TPMAObject{ + SignEncrypt: true, + FixedTPM: true, + FixedParent: true, + SensitiveDataOrigin: true, + UserWithAuth: true, + }, + AuthPolicy: tpm2.TPM2BDigest{}, + Parameters: tpm2.NewTPMUPublicParms( + tpm2.TPMAlgRSA, + &tpm2.TPMSRSAParms{ + Scheme: tpm2.TPMTRSAScheme{ + Scheme: tpm2.TPMAlgRSASSA, + Details: tpm2.NewTPMUAsymScheme( + tpm2.TPMAlgRSASSA, + &tpm2.TPMSSigSchemeRSASSA{ + HashAlg: tpm2.TPMAlgSHA256, + }, + ), + }, + KeyBits: 2048, + }, + ), + Unique: tpm2.NewTPMUPublicID( + tpm2.TPMAlgRSA, + &tpm2.TPM2BPublicKeyRSA{ + Buffer: make([]byte, 256), + }, + ), + } + + rsaKeyResponse, err := tpm2.CreateLoaded{ + ParentHandle: tpm2.NamedHandle{ + Handle: tpm2.TPMHandle(0x81000002), + Name: ersp.Name, + }, + // ParentHandle: tpm2.AuthHandle{ + // Handle: ersp.ObjectHandle, + // Name: ersp.Name, + // Auth: tpm2.PasswordAuth([]byte("")), + // }, + InPublic: tpm2.New2BTemplate(&rsaTemplate), + }.Execute(tpm) + + + + fmt.Printf("Create control response %v, %w\n",rsaKeyResponse,err) diff --git a/etc/scripts/tpmtest/tpmtest b/etc/scripts/tpmtest/tpmtest new file mode 100755 index 0000000..ed967b6 Binary files /dev/null and b/etc/scripts/tpmtest/tpmtest differ diff --git a/etc/scripts/tpmtest/tpmtest.go b/etc/scripts/tpmtest/tpmtest.go new file mode 100644 index 0000000..be8d42e --- /dev/null +++ b/etc/scripts/tpmtest/tpmtest.go @@ -0,0 +1,139 @@ +package main + +import ( + "fmt" + "os" + + "encoding/hex" + "encoding/base64" + + "github.com/google/go-tpm/tpm2/transport/linuxtpm" + "github.com/google/go-tpm/tpm2" +) + + + +func main() { + tpm,err := linuxtpm.Open("/dev/tpmrm0") + fmt.Printf("TPM %v, Error %w \n",tpm,err) + if err!=nil { + os.Exit(1) + } + + b := tpm2.GetRandom{32} + rsp,err := b.Execute(tpm) + fmt.Printf("GetRandom response %v, %w\n",rsp,err) + + p := tpm2.PCRRead{ + PCRSelectionIn: tpm2.TPMLPCRSelection{ + PCRSelections: []tpm2.TPMSPCRSelection{ + { + Hash: tpm2.TPMAlgSHA256, + PCRSelect: tpm2.PCClientCompatible.PCRs(0,1,2,3), + }, + }, + }, + } + prsp,err := p.Execute(tpm) + fmt.Printf("PCRRead response %v, %w\n",prsp,err) + if err==nil { + fmt.Printf("PCRUpdateCounter %v\nPCRSelection %v\nDigest %v\n",prsp.PCRUpdateCounter,prsp.PCRSelectionOut,prsp.PCRValues) + + digests := prsp.PCRValues.Digests + fmt.Printf("There is/are %v digest(s)\n",len(digests)) + + digest0 := digests[0] + fmt.Printf("Digest 0 is %v\n", digest0) + + hstr := hex.EncodeToString( []byte(digest0.Buffer)) + fmt.Printf("Digest 0 as hex is %v\n", hstr) + } + + + fmt.Println("\nAttempting to create the primary endorsement key, load and store it") + + // https://github.com/TPM2Nexus/tpm2-samples/blob/master/quote_verify/main.go + + primaryKey, err := tpm2.CreatePrimary{ + PrimaryHandle: tpm2.TPMRHEndorsement, + InPublic: tpm2.New2B(tpm2.RSASRKTemplate), + }.Execute(tpm) + + fmt.Printf(" EK: %w, %v\n", err,primaryKey) + fmt.Printf(" Object handle is %x\n",primaryKey.ObjectHandle) + fmt.Printf(" Name %s\n", base64.StdEncoding.EncodeToString(primaryKey.Name.Buffer)) + + + + rsaTemplate := tpm2.TPMTPublic{ + Type: tpm2.TPMAlgRSA, + NameAlg: tpm2.TPMAlgSHA256, + ObjectAttributes: tpm2.TPMAObject{ + SignEncrypt: true, + FixedTPM: true, + FixedParent: true, + SensitiveDataOrigin: true, + UserWithAuth: true, + }, + AuthPolicy: tpm2.TPM2BDigest{}, + Parameters: tpm2.NewTPMUPublicParms( + tpm2.TPMAlgRSA, + &tpm2.TPMSRSAParms{ + Scheme: tpm2.TPMTRSAScheme{ + Scheme: tpm2.TPMAlgRSASSA, + Details: tpm2.NewTPMUAsymScheme( + tpm2.TPMAlgRSASSA, + &tpm2.TPMSSigSchemeRSASSA{ + HashAlg: tpm2.TPMAlgSHA256, + }, + ), + }, + KeyBits: 2048, + }, + ), + } + + rsaKeyResponse, err := tpm2.CreateLoaded{ + ParentHandle: tpm2.AuthHandle{ + Handle: primaryKey.ObjectHandle, + Name: primaryKey.Name, + Auth: tpm2.PasswordAuth(nil), + }, + InPublic: tpm2.New2BTemplate(&rsaTemplate), + }.Execute(tpm) + + fmt.Printf(" AK: %w, %v\n", err,rsaKeyResponse) + fmt.Printf(" Object handle is %x\n",rsaKeyResponse.ObjectHandle) + fmt.Printf(" Name %s\n", base64.StdEncoding.EncodeToString(rsaKeyResponse.Name.Buffer)) + + + + fmt.Println("\nAttempting evict control on EK") + + vrsp, err := tpm2.EvictControl{ + Auth: tpm2.TPMRHOwner, + ObjectHandle: &tpm2.NamedHandle{ + Handle: primaryKey.ObjectHandle, + Name: primaryKey.Name, + }, + PersistentHandle: tpm2.TPMHandle(0x81000002), + }.Execute(tpm) + + fmt.Printf("Evict control response %v, %w\n",vrsp,err) + + fmt.Println("\nAttempting evict control on AK") + + vrsp, err = tpm2.EvictControl{ + Auth: tpm2.TPMRHOwner, + ObjectHandle: &tpm2.NamedHandle{ + Handle: rsaKeyResponse.ObjectHandle, + Name: rsaKeyResponse.Name, + }, + PersistentHandle: tpm2.TPMHandle(0x81000003), + }.Execute(tpm) + + fmt.Printf("Evict control response %v, %w\n",vrsp,err) + + +} + diff --git a/etc/standardintents/generateshas.sh b/etc/standardintents/generateshas.sh new file mode 100755 index 0000000..aa191ae --- /dev/null +++ b/etc/standardintents/generateshas.sh @@ -0,0 +1,6 @@ +#/bin/sh +sha1sum standardintents.json | cut -d " " -f 1 > standardintents.sha1 +sha224sum standardintents.json | cut -d " " -f 1 > standardintents.sha224 +sha256sum standardintents.json | cut -d " " -f 1 > standardintents.sha256 +sha384sum standardintents.json | cut -d " " -f 1 > standardintents.sha384 +sha512sum standardintents.json | cut -d " " -f 1 > standardintents.sha512 \ No newline at end of file diff --git a/etc/standardintents/standardintents.json b/etc/standardintents/standardintents.json index a0e9d8a..006c471 100644 --- a/etc/standardintents/standardintents.json +++ b/etc/standardintents/standardintents.json @@ -1,4 +1,46 @@ [ + { + "itemid": "ratsd::test::chares", + "name": "RATSD Chares call", + "description": "Test call to the RATSD daemon", + "function": "ratsd/chares", + "parameters": {} + }, + { + "itemid": "std::intent::sys::info", + "name": "System Information", + "description": "Collects basic system information", + "function": "sys/info", + "parameters": {} + }, + { + "itemid": "std::intent::uefi::eventlog", + "name": "UEFI Eventlog", + "description": "Retreives the UEFI Eventlog on Linux systems", + "function": "uefi/eventlog", + "parameters": {} + }, + { + "itemid": "std::intent::uefi::efivars", + "name": "UEFI EFI Variables", + "description": "Retreives the UEFI EFI Variables on Linux (and maybe Windows) systems", + "function": "uefi/efivars", + "parameters": {} + }, + { + "itemid": "std::intent::uefi::bootconfig", + "name": "UEFI Boot Configuration", + "description": "Retreives the UEFI Boot Configuration", + "function": "uefi/bootconfig", + "parameters": {} + }, + { + "itemid": "std::intent::linux::ima::asciilog", + "name": "Linux IMA ASCII Log", + "description": "Retrieves the ASCII Log generated by Linux Integrity Measurement Architecture", + "function": "ima/asciilog", + "parameters": {} + }, { "itemid": "std::intent::sha256::crtm::pcr0", "name": "x86 UEFI CRTM only", @@ -10,6 +52,13 @@ "bank": "sha256" } }, + { + "itemid": "std::intent::tpm::pcrs", + "name": "TPM 2.0 PCRs", + "description": "Returns the PCR values for all banks", + "function": "tpm2/pcrs", + "parameters":{} + }, { "itemid": "std::intent::sha256::crtm::firmware", "name": "x86 UEFI CRTM Firmware", @@ -24,7 +73,7 @@ { "itemid": "std::intent::sha256::crtm::bootloaderonly", "name": "x86 UEFI Bootloader Only", - "description": "The initial CRTM bootloader only measurement for x86 UEFI machines as stored in SHA256 PCRs", + "description": "The bootloader only measurement for x86 UEFI machines as stored in SHA256 PCRs", "function": "tpm2/quote", "parameters": { @@ -32,6 +81,28 @@ "bank": "sha256" } }, + { + "itemid": "std::intent::sha256::crtm::crtmplusbootloader", + "name": "x86 UEFI Bootloader and CRTM", + "description": "The bootloader and CRTM measurement for x86 UEFI machines as stored in SHA256 PCRs", + "function": "tpm2/quote", + "parameters": + { + "pcrSelection": "0,4,5", + "bank": "sha256" + } + }, + { + "itemid": "std::intent::sha256::crtm::srtmbootloader", + "name": "x86 UEFI SRTM and Bootloader", + "description": "The SRTM and bootloader measurements for x86 UEFI machines as stored in SHA256 PCRs", + "function": "tpm2/quote", + "parameters": + { + "pcrSelection": "0,1,2,3,4,5", + "bank": "sha256" + } + }, { "itemid": "std::intent::sha256::srtm", "name": "x86 UEFI SRTM", diff --git a/etc/standardintents/standardintents.sha1 b/etc/standardintents/standardintents.sha1 new file mode 100644 index 0000000..f7dc6a9 --- /dev/null +++ b/etc/standardintents/standardintents.sha1 @@ -0,0 +1 @@ +f51ab4780760494bacba980a05085df8ee06a67a diff --git a/etc/standardintents/standardintents.sha224 b/etc/standardintents/standardintents.sha224 new file mode 100644 index 0000000..1535b54 --- /dev/null +++ b/etc/standardintents/standardintents.sha224 @@ -0,0 +1 @@ +d66149cbc63d8996b2b05107a6eebf9d890bf44611877af9da9cc4f6 diff --git a/etc/standardintents/standardintents.sha256 b/etc/standardintents/standardintents.sha256 index dacd7bd..9a33990 100644 --- a/etc/standardintents/standardintents.sha256 +++ b/etc/standardintents/standardintents.sha256 @@ -1 +1 @@ -e02bb3a7f75e9fd4bdc826a089d23f6d1aaadda38640a409256d0c1459231582 standardintents.json +607b4f6c6fb685a49c23990972ff00542b5209124d6a65fcc66b85d9535103ef diff --git a/etc/standardintents/standardintents.sha384 b/etc/standardintents/standardintents.sha384 new file mode 100644 index 0000000..6c10683 --- /dev/null +++ b/etc/standardintents/standardintents.sha384 @@ -0,0 +1 @@ +465873f368dd09366233f653a1a8859165b4e5661b745ecccc3080213463ccb156ce63513d05b5c6bacfd7d93852635f diff --git a/etc/standardintents/standardintents.sha512 b/etc/standardintents/standardintents.sha512 new file mode 100644 index 0000000..46a39e7 --- /dev/null +++ b/etc/standardintents/standardintents.sha512 @@ -0,0 +1 @@ +2532291bb97c7f66bbab552cf242973abd1f9632dc621c9edca7c72d0890d4a416f290dc446ba9b521881aff20bc11220104b48b9fe7e43d5bd85886a63e6ba2 diff --git a/etc/tpmsetup/README.md b/etc/tpmsetup/README.md new file mode 100644 index 0000000..ff2d0c9 --- /dev/null +++ b/etc/tpmsetup/README.md @@ -0,0 +1,7 @@ +# TPM Setup + +See: https://github.com/iolivergithub/TPMCourse/blob/master/docs/keys.md#special-keys + +This script sets up the TPM's EK and AK keys in handles 0x810100EE and 0x81010AA + +It requires installation of the tpm2tools \ No newline at end of file diff --git a/etc/tpmsetup/tpmsetup.sh b/etc/tpmsetup/tpmsetup.sh new file mode 100644 index 0000000..a22b172 --- /dev/null +++ b/etc/tpmsetup/tpmsetup.sh @@ -0,0 +1,5 @@ +#/bin/sh +tpm2_createek -c 0x810100EE -G rsa -u ek.pub +tpm2_createak -C 0x810100EE -c ak.ctx -G rsa -g sha256 -s rsassa -u ak.pub -f pem -n ak.name +tpm2_evictcontrol -c ak.ctx 0x810100AA +tpm2_getcap handles-persistent \ No newline at end of file diff --git a/janeserver/Dockerfile b/janeserver/Dockerfile index bd67d2e..8540ed5 100644 --- a/janeserver/Dockerfile +++ b/janeserver/Dockerfile @@ -1,16 +1,15 @@ -FROM amd64/ubuntu:23.04 AS build-stage +FROM amd64/ubuntu:24.04 AS build-stage RUN apt-get update RUN apt-get install -y wget #Install Go -RUN ["wget","https://go.dev/dl/go1.22.4.linux-amd64.tar.gz"] -RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz -RUN export PATH=$PATH:/usr/local/go/bin - -# +# v 1.23.2 +RUN ["wget","https://go.dev/dl/go1.23.2.linux-amd64.tar.gz"] +RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go1.23.2.linux-amd64.tar.gz +RUN export PATH=$PATH:/usr/local/go/bin RUN mkdir -p /etc/apt/keyrings @@ -18,10 +17,10 @@ RUN ["wget", "https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.k RUN echo "deb [signed-by=/etc/apt/keyrings/intel-sgx-keyring.asc arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu jammy main" > /etc/apt/sources.list.d/intel-sgx.list RUN apt update -#RUN ERT_DEB=edgelessrt_0.4.1_amd64_ubuntu-22.04.deb -RUN ["wget","https://github.com/edgelesssys/edgelessrt/releases/download/v0.4.1/edgelessrt_0.4.1_amd64_ubuntu-22.04.deb"] -RUN apt-get install -y ./edgelessrt_0.4.1_amd64_ubuntu-22.04.deb build-essential cmake libssl-dev libsgx-dcap-default-qpl libsgx-dcap-ql libsgx-dcap-quote-verify +RUN ["wget","https://github.com/edgelesssys/edgelessrt/releases/download/v0.4.7/edgelessrt_0.4.7_amd64_ubuntu-24.04.deb"] + +RUN apt-get install -y ./edgelessrt_0.4.7_amd64_ubuntu-24.04.deb build-essential cmake libssl-dev libsgx-dcap-default-qpl libsgx-dcap-ql libsgx-dcap-quote-verify # Set destination for COPY WORKDIR /app @@ -31,13 +30,15 @@ COPY . /app # Download Go modules COPY go.mod go.sum ./ -RUN /usr/local/go/bin/go mod download -RUN /usr/local/go/bin/go mod tidy -RUN . /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=linux GOARCH=amd64 /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=docker'" -o /janeserver janeserver.go -RUN strip /janeserver +#These have been deprecated for the Makefile way of doing things +#RUN /usr/local/go/bin/go mod download +#RUN /usr/local/go/bin/go mod tidy +#RUN . /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=linux GOARCH=amd64 /usr/local/go/bin/go #build -ldflags="-X 'main.BUILD=docker'" -o /janeserver janeserver.go +#RUN strip /janeserver +RUN make build -FROM amd64/ubuntu:23.04 +FROM amd64/ubuntu:24.04 RUN apt-get update RUN apt-get install -y libssl-dev diff --git a/janeserver/Makefile b/janeserver/Makefile new file mode 100644 index 0000000..595dc7e --- /dev/null +++ b/janeserver/Makefile @@ -0,0 +1,30 @@ +OS=linux +ARCH=amd64 +BINARY_NAME=janeserver +PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled + + +build: libs fmt + . /opt/edgelessrt/share/openenclave/openenclaverc && GOOS=${OS} GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + strip ${BINARY_NAME} + ls -l --color=auto ${BINARY_NAME} + +fmt: + go fmt ./... + +vet: + . /opt/edgelessrt/share/openenclave/openenclaverc && go vet -composites=false ./... + +libs: + go get -u + go mod tidy -v + go mod verify + +run: + ./${BINARY_NAME} + +clean: + go clean -r + rm ${BINARY_NAME} diff --git a/janeserver/config.yaml b/janeserver/config.yaml index 5d1f36e..1d6b3d1 100644 --- a/janeserver/config.yaml +++ b/janeserver/config.yaml @@ -18,7 +18,8 @@ rest: port: 8520 crt: temporary.crt key: temporary.key - usehttp: false + usehttp: true + listenon: 0.0.0.0 #Web Interface Configuration web: @@ -26,6 +27,7 @@ web: crt: temporary.crt key: temporary.key usehttp: true + listenon: 0.0.0.0 #Web Interface Configuration diff --git a/janeserver/configuration/configuration.go b/janeserver/configuration/configuration.go index e04ad6e..dd067d1 100644 --- a/janeserver/configuration/configuration.go +++ b/janeserver/configuration/configuration.go @@ -27,6 +27,8 @@ import ( //#REST Interface Configuration //rest: // port: 8520 -- Port to use for the REST API, default is 8520 +// listenOn: 0.0.0.0 -- Which addresses to listen on, default is 0.0.0.0 + // crt: temporary.crt -- File containing the certificate to use for the HTTPS server // key: temporary.key -- File containing the private key for the HTTPS server // usehttp: true -- Use HTTP (true) instead of HTTPS. Default is false @@ -45,16 +47,18 @@ type ConfigurationStruct struct { ClientID string } Rest struct { - Port string - Crt string - Key string - UseHTTP bool + Port string + Crt string + Key string + UseHTTP bool + ListenOn string } Web struct { - Port string - Crt string - Key string - UseHTTP bool + Port string + Crt string + Key string + UseHTTP bool + ListenOn string } X3270 struct { Port string @@ -80,11 +84,11 @@ func SetupConfiguration(f string) { configFile, err := ioutil.ReadFile(f) if err != nil { - panic(fmt.Sprintf("Configuration file missing. Exiting with error ", err)) + panic(fmt.Sprintf("Configuration file missing. Exiting with error %v", err.Error())) } err = yaml.Unmarshal(configFile, &ConfigData) if err != nil { - panic(fmt.Sprintf("Unable to parse configuration file. Exiting with error ", err)) + panic(fmt.Sprintf("Unable to parse configuration file. Exiting with error %v", err.Error())) } } diff --git a/janeserver/datalayer/mqtt.go b/janeserver/datalayer/mqtt.go index 6257fee..61732ca 100644 --- a/janeserver/datalayer/mqtt.go +++ b/janeserver/datalayer/mqtt.go @@ -15,7 +15,7 @@ var connectHandler mqtt.OnConnectHandler = func(client mqtt.Client) { } var connectLostHandler mqtt.ConnectionLostHandler = func(client mqtt.Client, err error) { - fmt.Println("JANE: MQTT connection lost. Error %v", err) + fmt.Printf("JANE: MQTT connection lost. Error %v", err.Error()) } func initialiseMessaging() { diff --git a/janeserver/go.mod b/janeserver/go.mod index 1e18077..bc6586d 100644 --- a/janeserver/go.mod +++ b/janeserver/go.mod @@ -1,32 +1,34 @@ module a10 -go 1.22 +go 1.24.0 -toolchain go1.22.2 +toolchain go1.24.2 require ( - github.com/eclipse/paho.mqtt.golang v1.4.3 + github.com/eclipse/paho.mqtt.golang v1.5.1 github.com/google/uuid v1.6.0 - github.com/labstack/echo/v4 v4.12.0 - github.com/racingmars/go3270 v0.0.0-20231111230320-21f273b327b8 - go.mongodb.org/mongo-driver v1.15.1 - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 + github.com/labstack/echo/v4 v4.13.4 + github.com/racingmars/go3270 v0.9.4 + go.mongodb.org/mongo-driver v1.17.4 + golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b gopkg.in/yaml.v3 v3.0.1 ) -require github.com/miekg/pkcs11 v1.1.1 +require ( + github.com/miekg/pkcs11 v1.1.1 + github.com/mitchellh/mapstructure v1.5.0 +) -require github.com/go-jose/go-jose/v4 v4.0.2 // indirect +require github.com/go-jose/go-jose/v4 v4.1.3 // indirect require ( - github.com/edgelesssys/ego v1.5.3 - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-tpm v0.9.1 + github.com/edgelesssys/ego v1.8.0 + github.com/golang/snappy v1.0.0 // indirect + github.com/google/go-tpm v0.9.6 github.com/gorilla/websocket v1.5.3 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -34,11 +36,11 @@ require ( github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.14.0 // indirect ) diff --git a/janeserver/go.mod.bak2 b/janeserver/go.mod.bak2 deleted file mode 100644 index f9b90da..0000000 --- a/janeserver/go.mod.bak2 +++ /dev/null @@ -1,42 +0,0 @@ -module a10 - - - -require ( - github.com/eclipse/paho.mqtt.golang v1.4.3 - github.com/google/uuid v1.6.0 - github.com/labstack/echo/v4 v4.12.0 - github.com/racingmars/go3270 v0.0.0-20231111230320-21f273b327b8 - go.mongodb.org/mongo-driver v1.15.1 - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 - gopkg.in/yaml.v3 v3.0.1 -) - -require github.com/miekg/pkcs11 v1.1.1 - -require github.com/go-jose/go-jose/v4 v4.0.2 // indirect - -require ( - github.com/edgelesssys/ego v1.5.3 - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/go-tpm v0.9.1 - github.com/gorilla/websocket v1.5.3 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/labstack/gommon v0.4.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/montanaflynn/stats v0.7.1 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.2 // indirect - github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect -) diff --git a/janeserver/go.sum b/janeserver/go.sum index 09151e9..9f989be 100644 --- a/janeserver/go.sum +++ b/janeserver/go.sum @@ -1,44 +1,45 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= -github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= -github.com/edgelesssys/ego v1.5.3 h1:Ec8lAjGQnKT9s+4U4o+AdSp2tYH5JN99cJMnNAfMEuU= -github.com/edgelesssys/ego v1.5.3/go.mod h1:xpgzdPWmxBGeF/d6X3Nk78hSjUfW6f05X28/jkXLRzE= -github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= -github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE= +github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU= +github.com/edgelesssys/ego v1.8.0 h1:g/02JeTC/vajbAfFqxckwSC+siKno/R4H/Em2YsHheU= +github.com/edgelesssys/ego v1.8.0/go.mod h1:fg0M/xfLWnrkoD2OZpY9xmltGlAPFsIiUmyHTuCS7zo= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-tpm v0.9.1 h1:0pGc4X//bAlmZzMKf8iz6IsDo1nYTbYJ6FZN/rg4zdM= -github.com/google/go-tpm v0.9.1/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm v0.9.6 h1:Ku42PT4LmjDu1H5C5ISWLlpI1mj+Zq7sPGKoRw2XROA= +github.com/google/go-tpm v0.9.6/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc= +github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= -github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA= +github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/racingmars/go3270 v0.0.0-20231111230320-21f273b327b8 h1:Q/ZaYUncS0LXd60kQa9LR5ZcWv1Wn6aIm1jKTUVEIS4= -github.com/racingmars/go3270 v0.0.0-20231111230320-21f273b327b8/go.mod h1:TVzW7wx9lk51ziz/RKKkOj1Kc3NrPJkqMWJFiH5p3pI= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/racingmars/go3270 v0.9.4 h1:7abINswMuOW5Pe8iYCw8UUThcaU2uXahwxv/pgYYMmE= +github.com/racingmars/go3270 v0.9.4/go.mod h1:JCzKbsCGdevsd+2iLMRw3Cd+Wk7vmBeGlnfHmeJEcsU= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= @@ -49,46 +50,45 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo= -github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.15.1 h1:l+RvoUOoMXFmADTLfYDm7On9dRm7p4T80/lEQM+r7HU= -go.mongodb.org/mongo-driver v1.15.1/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/janeserver/janeserver.go b/janeserver/janeserver.go index c15de73..e8caa2f 100644 --- a/janeserver/janeserver.go +++ b/janeserver/janeserver.go @@ -1,12 +1,16 @@ -// Attestation Engine A10 JANE, Febrary 2024 onwards. +// Attestation Engine A10 JANE, February 2024 onwards. // The main package starts the various interfaces: REST, MQTT and links to the database system package main import ( + "context" "flag" "fmt" + "os" + "os/signal" "runtime" - "sync" + _ "sync" + "syscall" "a10/configuration" "a10/datalayer" @@ -34,18 +38,18 @@ var flagREST = flag.Bool("startREST", true, "Start the REST API, defaults to tru var flagWEB = flag.Bool("startWebUI", true, "Start the HTML Web UI, defaults to true") var flagX3270 = flag.Bool("startx3270", true, "Start the X3270 UI, defaults to true") -var configFile = flag.String("config", "./config.yaml", "Location and name of the configuration file") +var configFile = flag.String("config", "./config.yaml", "Location and name of the configuration file, default to a config.yaml in the current directory") // Provides the standard welcome message to stdout. func welcomeMessage() { fmt.Printf("\n") - fmt.Printf("+========================================================================================\n") + fmt.Printf("+========================================================\n") fmt.Printf("| JANESERVER version\n") fmt.Printf("| + %v O/S on %v\n", runtime.GOOS, runtime.GOARCH) fmt.Printf("| + version %v, build %v\n", VERSION, BUILD) fmt.Printf("| + runing with name %v\n", configuration.ConfigData.System.Name) fmt.Printf("| + session identifier is %v\n", RUNSESSION) - fmt.Printf("+========================================================================================\n\n") + fmt.Printf("+========================================================\n") } // This starts everything...here we "go" <- great pun! :-) @@ -62,6 +66,8 @@ func main() { // Ok, we're up...let's log this. msg := fmt.Sprintf("Starting: %v, build %v, OS %v, ARCH %v", VERSION, BUILD, runtime.GOOS, runtime.GOARCH) logging.MakeLogEntry("SYS", "startup/INIT", RUNSESSION, configuration.ConfigData.System.Name, msg) + msg = fmt.Sprintf("Command line contained %v items: %v", len(os.Args), os.Args) + logging.MakeLogEntry("SYS", "startup/INIT", RUNSESSION, "command line", msg) welcomeMessage() @@ -77,31 +83,49 @@ func main() { msg = fmt.Sprintf("DB,MQTT,Rules initialised. Starting services: web %v, rest %v, x3720 %v", *flagWEB, *flagREST, *flagX3270) logging.MakeLogEntry("SYS", "startup", RUNSESSION, configuration.ConfigData.System.Name, msg) + // start the internal services + internalservices() + + logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "JANE "+VERSION, "Final message: We apologise for the inconvience (bring 42 towels)") + fmt.Println("+=== Final message: We apologise for the inconvience (42). Next time, bring a towel ===") + +} + +func internalservices() { // Start (or not) the various internal services // As these run as threads, we put them in a wait group // Need to implement a proper graceful shutdown mechanism // - // If any of these internal services fail to start, then the system will panic + // If any of these internal services fail to start, then the system may panic + + // Create a context that can be canceled + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // Ensure cancel is called at the end to clean up - var wg sync.WaitGroup + // Channel to listen for system signals (e.g., Ctrl+C) + sigChan := make(chan os.Signal, 1) + signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) + // Bring up the services if *flagX3270 == true { - wg.Add(1) - go x3270.StartX3270() + go x3270.StartX3270(ctx) } if *flagREST == true { - wg.Add(1) - go restapi.StartRESTInterface() + go restapi.StartRESTInterface(ctx) } if *flagWEB == true { - wg.Add(1) - go webui.StartWebUI() + go webui.StartWebUI(ctx) } - wg.Wait() - // ...and exit here (if graceful!) which does not happen in the current version + // Wait for an interrupt signal to initiate graceful shutdown + select { + case <-sigChan: + // Handle shutdown signal (Ctrl+C or SIGTERM) + logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "JANE "+VERSION, "Received shutdown signal. Shutting down gracefully") + fmt.Println("+=== Received shutdown signal. Shutting down gracefully ===") - logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "JANE "+VERSION, "Clean shutdown sequence completed. System is now stopped") - fmt.Println("+=== Exiting. ================================================") + // Cancel the context to notify all goroutines to stop + cancel() + } } diff --git a/janeserver/logging/logging.go b/janeserver/logging/logging.go index 6b4ed0d..33fa18e 100644 --- a/janeserver/logging/logging.go +++ b/janeserver/logging/logging.go @@ -18,7 +18,7 @@ func MakeLogEntry(ch string, op string, itemid string, itemtype string, message logentry := structures.LogEntry{utilities.MakeID(), utilities.MakeTimestamp(), ch, op, itemid, itemtype, message, []byte{}} if digest, err := utilities.MakeSHA256(logentry); err != nil { - log.Printf("WARNING: Encoding log entry failed with %w. Entry not made.", err) + log.Printf("WARNING: Encoding log entry failed with %v. Entry not made.", err.Error()) } else { logentry.Hash = digest @@ -58,7 +58,7 @@ func writeToLogfile(wgrp *sync.WaitGroup, l structures.LogEntry) { defer f.Close() if _, err := f.WriteString(makeCSVText(l)); err != nil { - log.Println("Error writring to log file ", configuration.ConfigData.Logging.LogFileLocation) + log.Println("Error writing to log file ", configuration.ConfigData.Logging.LogFileLocation) } wgrp.Done() diff --git a/janeserver/operations/attestation.go b/janeserver/operations/attestation.go index 14f2e39..5d391b8 100644 --- a/janeserver/operations/attestation.go +++ b/janeserver/operations/attestation.go @@ -14,9 +14,9 @@ type hashablePartClaim struct { } // This function calls the attestation mechanism that eventually calls the TA on some client -// ItemIDs for Element, Policy and String are provided in eid, pid and sid +// ItemIDs for Element, intent and String are provided in eid, pid and sid // A map of additional parameters in aps -func Attest(element structures.Element, policy structures.Intent, session structures.Session, aps map[string]interface{}) (string, error) { +func Attest(element structures.Element, endpointname string, intent structures.Intent, session structures.Session, aps map[string]interface{}) (string, error) { var body map[string]interface{} = make(map[string]interface{}) @@ -32,8 +32,19 @@ func Attest(element structures.Element, policy structures.Intent, session struct // Step 1 ****************************************************** - protocol := element.Protocol - protocolObject, _ := GetProtocol(protocol) + // Get the Protocol from the endpoint + + endpoint, ok := utilities.SelectEndpoint(element, endpointname) + if ok == false { + return "", fmt.Errorf("No such endpoint %v", endpointname) + } + + protocol := endpoint.Protocol + protocolObject, perr := GetProtocol(protocol) + + if perr != nil { + return "", perr + } // TODO: Need to check that the protocol exists here otherwise the acall below fails with a panic @@ -44,7 +55,7 @@ func Attest(element structures.Element, policy structures.Intent, session struct // Step 3 ****************************************************** aCALL := protocolObject.CallFunction - returnedBody, ips, bodytype := aCALL(element, policy, session, aps) + returnedBody, ips, bodytype := aCALL(element, endpoint, intent, session, aps) if bodytype == "*ERROR" { body["ERROR"] = returnedBody @@ -60,7 +71,7 @@ func Attest(element structures.Element, policy structures.Intent, session struct // NB: we have body and bodytype from above timing := structures.Timing{claimTimerStart, claimTimerFinish} - header := structures.ClaimHeader{element, policy, session, timing, aps, ips} + header := structures.ClaimHeader{element, intent, endpointname, endpoint, session, timing, aps, ips} footer, _ := hashAndSignClaim(hashablePartClaim{bodytype, header, body}) c := structures.Claim{"", bodytype, header, body, footer} @@ -73,7 +84,7 @@ func Attest(element structures.Element, policy structures.Intent, session struct return "", fmt.Errorf("Error adding claim, session %v might still be open: %w", sid, err) } - fmt.Printf("Added claim %v\n", cid) + //fmt.Printf("Added claim %v\n", cid) // if AddClaim fails, we have a bigger problem, see above note // If there is an error here, then we need a new claim type of "internal error" diff --git a/janeserver/operations/claims.go b/janeserver/operations/claims.go index e4d1bea..85b1563 100644 --- a/janeserver/operations/claims.go +++ b/janeserver/operations/claims.go @@ -54,13 +54,11 @@ func GetClaimsAll() ([]structures.Claim, error) { var claims []structures.Claim filter := bson.D{{}} // Get all - options := options.Find().SetSort(bson.D{{"header.timing.requested", -1}}) + options := options.Find().SetSort(bson.D{{"header.timing.requested", -1}}).SetLimit(2000) dbcursor, _ := datalayer.DB.Collection("claims").Find(context.TODO(), filter, options) dbcursorerror := dbcursor.All(context.TODO(), &claims) - fmt.Printf("\n********\nClaims\n error %w \n claims %v \n*** \n", claims, dbcursorerror) - return claims, dbcursorerror } @@ -71,7 +69,6 @@ func GetClaimsByElementID(eid string, maximumAmount int64) ([]structures.Claim, return claims, fmt.Errorf("Maximum amount must be a positive number") } - fmt.Println("Getting for claim by element eid = %v\n", eid) filter := bson.D{{"header.element.itemid", eid}} // TODO search for itemIDs only options := options.Find().SetSort(bson.D{{"header.timing.requested", -1}}).SetLimit(maximumAmount) dbcursor, _ := datalayer.DB.Collection("claims").Find(context.TODO(), filter, options) diff --git a/janeserver/operations/elements.go b/janeserver/operations/elements.go index 00686d9..fc70466 100644 --- a/janeserver/operations/elements.go +++ b/janeserver/operations/elements.go @@ -4,6 +4,7 @@ package operations import ( "context" + "fmt" "a10/datalayer" "a10/logging" @@ -27,6 +28,8 @@ func AddElement(e structures.Element) (string, error) { return "", ErrorItemIDIncluded } else { e.ItemID = utilities.MakeID() + e.RecordHistory = recordInformationCreation() + fmt.Printf("New element %v\n", e) _, dberr := datalayer.DB.Collection("elements").InsertOne(context.TODO(), e) logging.MakeLogEntry("IM", "add", e.ItemID, "element", "") @@ -36,6 +39,7 @@ func AddElement(e structures.Element) (string, error) { // UpdateElement requires the complete structure, that is, it replaces the structure with the given itemid func UpdateElement(replacement structures.Element) error { + replacement.RecordHistory = recordInformationUpdate(replacement.RecordHistory) filter := bson.D{{"itemid", replacement.ItemID}} updateresult, err := datalayer.DB.Collection("elements").ReplaceOne(context.TODO(), filter, replacement) @@ -52,6 +56,7 @@ func UpdateElement(replacement structures.Element) error { // DeleteElement takes an itemid as input func DeleteElement(itemid string) error { filter := bson.D{{"itemid", itemid}} + deleteresult, err := datalayer.DB.Collection("elements").DeleteOne(context.TODO(), filter) if err != nil { @@ -77,6 +82,18 @@ func GetElements() ([]structures.ID, error) { return elems, dbcursorerror } +// GetElements returns a map of itemids in the ID structure. If this structure is an empty map then no elements exist in the database. +func GetElementsSummary() ([]structures.ElementSummary, error) { + var elems []structures.ElementSummary + + filter := bson.D{{}} // Get all + options := options.Find().SetProjection(bson.D{{"itemid", 1}, {"name", 1}, {"endpoints", 1}}).SetSort(bson.D{{"name", 1}}) + dbcursor, _ := datalayer.DB.Collection("elements").Find(context.TODO(), filter, options) + dbcursorerror := dbcursor.All(context.TODO(), &elems) + + return elems, dbcursorerror +} + // GetElementsAll returns a map of every element. If this structure is an empty map then no elements exist in the database. // This is only meant to be used sparingly, eg: when quering the UI to reduce load on the database func GetElementsAll() ([]structures.Element, error) { diff --git a/janeserver/operations/expectedValues.go b/janeserver/operations/expectedValues.go index b81ac6c..04defcb 100644 --- a/janeserver/operations/expectedValues.go +++ b/janeserver/operations/expectedValues.go @@ -27,6 +27,8 @@ func AddExpectedValue(e structures.ExpectedValue) (string, error) { return "", ErrorItemIDIncluded } else { e.ItemID = utilities.MakeID() + e.RecordHistory = recordInformationCreation() + _, dberr := datalayer.DB.Collection("expectedvalues").InsertOne(context.TODO(), e) logging.MakeLogEntry("IM", "add", e.ItemID, "expectedvalue", "") @@ -36,6 +38,7 @@ func AddExpectedValue(e structures.ExpectedValue) (string, error) { // UpdateExpectedValue requires the complete structure, that is, it replaces the structure with the given itemid func UpdateExpectedValue(replacement structures.ExpectedValue) error { + replacement.RecordHistory = recordInformationUpdate(replacement.RecordHistory) filter := bson.D{{"itemid", replacement.ItemID}} updateresult, err := datalayer.DB.Collection("expectedvalues").ReplaceOne(context.TODO(), filter, replacement) @@ -146,23 +149,33 @@ func GetExpectedValuesByElement(name string) ([]structures.ExpectedValue, error) // mongo returns to you ... no checking, you are on your own but you were warned NOT to have more // than one eid,pid pair for an EV, so it is your fault. // I *may* put in checking for this one day....but I have other things to do :-) -func GetExpectedValueByElementAndPolicy(eid string, pid string) (structures.ExpectedValue, error) { +func GetExpectedValueByElementAndPolicy(eid string, pid string, epn string) (structures.ExpectedValue, error) { var elem structures.ExpectedValue + //fmt.Printf("GetExpectedValueByElementAndPolicy %v %v %v\n", eid, pid, epn) + // discard the cursor, it will be an empty entry if nothing exists filter := bson.D{ {"$and", bson.A{ bson.D{{"elementid", eid}}, bson.D{{"intentid", pid}}, + bson.D{{"endpointname", epn}}, }, }, } - dbcursorerror := datalayer.DB.Collection("expectedvalues").FindOne(context.TODO(), filter).Decode(&elem) + + //dbcursorerror := datalayer.DB.Collection("expectedvalues").FindOne(context.TODO(), filter).Decode(&elem) + datalayer.DB.Collection("expectedvalues").FindOne(context.TODO(), filter).Decode(&elem) + + //fmt.Printf("got the cursor, error = %v \n", dbcursorerror) + //fmt.Printf("elem = %v\n", elem) if elem.ItemID == "" { + //fmt.Println("I am returning the dbcursorerror from earlier") return structures.ExpectedValue{}, ErrorItemNotFound } else { - return elem, dbcursorerror + //fmt.Printf("elem ItemID = %v\n", elem.ItemID) + return elem, nil } } diff --git a/janeserver/operations/intents.go b/janeserver/operations/intents.go index 89dcf6e..0a7e925 100644 --- a/janeserver/operations/intents.go +++ b/janeserver/operations/intents.go @@ -18,7 +18,7 @@ func CountIntents() int64 { return datalayer.Count("policies") } -// AddPolicy is a function that takes and element structure that has a BLANK Itemid field (empty string) and stores that +// AddIntent is a function that takes and element structure that has a BLANK Itemid field (empty string) and stores that // element in some database // Successful storage returns the itemid for that element and a nil error. // An error is returned if an item id is given as part of the input structure. @@ -48,7 +48,6 @@ func UpdateIntent(replacement structures.Intent) error { return nil } - } // DeleteElement takes an itemid as input @@ -65,7 +64,6 @@ func DeleteIntent(itemid string) error { return nil } - } // GetElements returns a map of itemids in the ID structure. If this structure is an empty map then no elements exist in the database. @@ -99,11 +97,7 @@ func GetIntentByItemID(itemid string) (structures.Intent, error) { filter := bson.D{{"itemid", itemid}} dbcursorerror := datalayer.DB.Collection("intents").FindOne(context.TODO(), filter).Decode(&pol) - if pol.ItemID == "" { - return structures.Intent{}, ErrorItemNotFound - } else { - return pol, dbcursorerror - } + return pol, dbcursorerror } // GetElementByName returns all elements with the given name or an empty list. @@ -117,3 +111,28 @@ func GetIntentsByName(name string) ([]structures.Intent, error) { return pol, dbcursorerror } + +// AddStandardIntent is a function that takes and element structure that has a FILLED IN Itemid field +// and then replaces any existing version of that intent +func AddStandardIntent(stdintent structures.Intent) { + _, err := GetIntentByItemID(stdintent.ItemID) + + if err == nil { + dberr := UpdateIntent(stdintent) + if dberr == nil { + logging.MakeLogEntry("IM", "update", stdintent.ItemID, "stdintent", "update successful for "+stdintent.ItemID) + } else { + logging.MakeLogEntry("IM", "update", stdintent.ItemID, "stdintent", "update FAILED due to "+dberr.Error()) + } + + } else { + // we don't call AddIntent because it expects NO itemid and automatically generates one + // which is what we don't want here. + _, dberr := datalayer.DB.Collection("intents").InsertOne(context.TODO(), stdintent) + if dberr == nil { + logging.MakeLogEntry("IM", "add", stdintent.ItemID, "stdintent", "add successful for "+stdintent.ItemID) + } else { + logging.MakeLogEntry("IM", "add", stdintent.ItemID, "stdintent", "add FAILED due to "+dberr.Error()) + } + } +} diff --git a/janeserver/operations/log.go b/janeserver/operations/log.go index 3248e60..ac61d82 100644 --- a/janeserver/operations/log.go +++ b/janeserver/operations/log.go @@ -2,7 +2,6 @@ package operations import ( "context" - "fmt" "a10/datalayer" "a10/structures" @@ -32,7 +31,7 @@ func GetLogEntriesSince(duration string) ([]structures.LogEntry, error) { var logentries []structures.LogEntry ts := utilities.TimeStampHoursAgo(duration) - fmt.Printf("Duration is %v, ts is %v\n", duration, ts) + //fmt.Printf("Duration is %v, ts is %v\n", duration, ts) filter := bson.D{{"timestamp", bson.D{{"$gt", ts}}}} // Get all since given point in time diff --git a/janeserver/operations/opaqueobjects.go b/janeserver/operations/opaqueobjects.go index ddf4dea..1ade107 100644 --- a/janeserver/operations/opaqueobjects.go +++ b/janeserver/operations/opaqueobjects.go @@ -15,14 +15,16 @@ import ( ) func CountOpaqueOjects() int64 { - return datalayer.Count("hashes") + return datalayer.Count("opaqueobjects") } func AddOpaqueObject(h structures.OpaqueObject) (string, error) { options := options.Update().SetUpsert(true) filter := bson.D{{"value", h.Value}} - //update := bson.D{{ "$set", bson.D{{ h }}}} - _, dberr := datalayer.DB.Collection("opaqueobjects").UpdateOne(context.TODO(), filter, h, options) + update := bson.D{{"$set", h}} + + _, dberr := datalayer.DB.Collection("opaqueobjects").UpdateOne(context.TODO(), filter, update, options) + msg := fmt.Sprintf("%s,%s", h.Type, h.ShortDescription) logging.MakeLogEntry("IM", "add", h.Value, "object", msg) return h.Value, dberr diff --git a/janeserver/operations/recordhistory.go b/janeserver/operations/recordhistory.go new file mode 100644 index 0000000..2c5182e --- /dev/null +++ b/janeserver/operations/recordhistory.go @@ -0,0 +1,21 @@ +package operations + +import ( + "a10/structures" + "a10/utilities" +) + +func recordInformationCreation() structures.RecordHistory { + return structures.RecordHistory{Created: utilities.MakeTimestamp()} +} + +func recordInformationUpdate(a structures.RecordHistory) structures.RecordHistory { + a.LastUpdated = utilities.MakeTimestamp() + return a +} + +func recordInformationArchived(a structures.RecordHistory, reason string) structures.RecordHistory { + a.Archived = utilities.MakeTimestamp() + a.Reason = reason + return a +} diff --git a/janeserver/operations/results.go b/janeserver/operations/results.go index d876254..b471bea 100644 --- a/janeserver/operations/results.go +++ b/janeserver/operations/results.go @@ -50,7 +50,7 @@ func GetResultsAll() ([]structures.Result, error) { var results []structures.Result filter := bson.D{{}} // Get all - options := options.Find().SetSort(bson.D{{"verifiedat", -1}}) + options := options.Find().SetSort(bson.D{{"verifiedat", -1}}).SetLimit(2000) dbcursor, _ := datalayer.DB.Collection("results").Find(context.TODO(), filter, options) dbcursorerror := dbcursor.All(context.TODO(), &results) @@ -60,10 +60,10 @@ func GetResultsAll() ([]structures.Result, error) { func GetResultsByElementID(eid string, maximumAmount int64) ([]structures.Result, error) { var Results []structures.Result - fmt.Printf("getting results for %v\n", eid) + //fmt.Printf("getting results for %v\n", eid) filter := bson.D{{"elementid", eid}} // Get all // TODO search for itemIDs only - options := options.Find().SetSort(bson.D{{"verifiedAt", -1}}).SetLimit(maximumAmount) + options := options.Find().SetSort(bson.D{{"verifiedat", -1}}).SetLimit(maximumAmount) dbcursor, _ := datalayer.DB.Collection("results").Find(context.TODO(), filter, options) dbcursorerror := dbcursor.All(context.TODO(), &Results) diff --git a/janeserver/operations/sessions.go b/janeserver/operations/sessions.go index 0c25223..0e4493e 100644 --- a/janeserver/operations/sessions.go +++ b/janeserver/operations/sessions.go @@ -53,7 +53,7 @@ func CloseSession(itemid string) error { //Get the session, return error if not found session, err := GetSessionByItemID(itemid) if err != nil { - return fmt.Errorf("Element not found %v : %v", itemid, err) + return fmt.Errorf("Session not found %v : %v", itemid, err) } //Check if the session isn't already closed diff --git a/janeserver/operations/signingFunctions.go b/janeserver/operations/signingFunctions.go index e4468c0..6e4c99b 100644 --- a/janeserver/operations/signingFunctions.go +++ b/janeserver/operations/signingFunctions.go @@ -15,7 +15,7 @@ var publickey *rsa.PublicKey var privatekey *rsa.PrivateKey func init() { - fmt.Printf("generating private, public key pair for claim signing - just for this session so no chance to verify later. THese keys MUST be external\n") + fmt.Printf("WARNING: generating private, public key pair for claim signing - just for this session so no chance to verify later. These keys MUST be external\n") privatekey, _ = rsa.GenerateKey(rand.Reader, 2048) publickey = &privatekey.PublicKey diff --git a/janeserver/operations/verification.go b/janeserver/operations/verification.go index d72ed5a..2ea2e78 100644 --- a/janeserver/operations/verification.go +++ b/janeserver/operations/verification.go @@ -2,7 +2,6 @@ package operations import ( "fmt" - "reflect" "a10/structures" "a10/utilities" @@ -38,24 +37,26 @@ func checkRuleObjectExists(rule structures.Rule) (structures.ResultValue, string } func getEV(claim structures.Claim, rule structures.Rule) (structures.ExpectedValue, error) { - fmt.Println("Step 2 - getting EV") + //fmt.Println("Step 2 - getting EV") // if the rule does need an EV, then we get it and return whatever comes back // if err is not nil then there was some error, usualy no EV for that E,P pair // but it could be something worse, eg: datalayer failure, but this is unlikely - fmt.Println(" Rule needs EV is %v", rule.NeedsEV) + //fmt.Printf(" Rule needs EV is %v\n", rule.NeedsEV) if rule.NeedsEV == true { e := claim.Header.Element.ItemID p := claim.Header.Intent.ItemID + n := claim.Header.EndpointName - fmt.Println(" e = %v", claim.Header.Element.ItemID) - fmt.Println(" p = %v", claim.Header.Intent.ItemID) + //fmt.Printf(" e = %v\n", claim.Header.Element.ItemID) + //fmt.Printf(" p = %v\n", claim.Header.Intent.ItemID) + //fmt.Printf(" n = %v\n", claim.Header.EndpointName) - ev, err := GetExpectedValueByElementAndPolicy(e, p) + ev, err := GetExpectedValueByElementAndPolicy(e, p, n) - fmt.Println(" GET EV error=%v, ev=%v", err, ev) + //fmt.Printf(" GET EV error=%v, ev=%v\n", err, ev) return ev, err } @@ -79,38 +80,38 @@ func Verify(claim structures.Claim, rule structures.Rule, session structures.Ses returnedRV, returnedMSG = checkClaimError(claim) eid = claim.Header.Element.ItemID - fmt.Printf("Verify eid %v\n", eid) + //fmt.Printf("Verify eid %v\n", eid) // if we are still unset then we proceed with the verification if returnedRV == structures.UnsetResultValue { - fmt.Println("dealing with the ev") + //fmt.Println("dealing with the ev") ev, err := getEV(claim, rule) if err != nil { - fmt.Println("dealing with the ev") + //fmt.Println("dealing with the ev") returnedRV = structures.MissingExpectedValue - returnedMSG = fmt.Sprintf("Rule %v requries an expected value for e,p pair %v and %v and one was not found: %w", rule.Name, claim.Header.Element.ItemID, claim.Header.Intent.ItemID, err.Error()) + returnedMSG = fmt.Sprintf("Rule %v requires an expected value for e,p pair %v and %v and one was not found: %v", rule.Name, claim.Header.Element.ItemID, claim.Header.Intent.ItemID, err) } else { // Now - fmt.Printf("Calling %v with %v %v %v \n", rule.Name, ev, session, rps) - fmt.Printf("Calling %v with %v %v %v \n", reflect.TypeOf(rule.Name), reflect.TypeOf(ev), reflect.TypeOf(session), reflect.TypeOf(rps)) + //fmt.Printf("Calling %v with %v %v %v \n", rule.Name, ev, session, rps) + //fmt.Printf("Calling %v with %v %v %v \n", reflect.TypeOf(rule.Name), reflect.TypeOf(ev), reflect.TypeOf(session), reflect.TypeOf(rps)) aCALL := rule.CallFunction returnedRV, returnedMSG, err = aCALL(claim, rule.Name, ev, session, rps) if err != nil { - fmt.Println("Step 3 -err") + //fmt.Println("Step 3 -err") returnedRV = structures.VerifyCallFailure - returnedMSG = fmt.Sprintf("Rule %v call failed with message %v and error %w", rule.Name, returnedMSG, err.Error()) // this should be the returnedMSG form the line above + returnedMSG = fmt.Sprintf("Rule %v call failed with message %v and error %v", rule.Name, returnedMSG, err) // this should be the returnedMSG form the line above } } } // Step 4 ****************************************************** - fmt.Println("Step 4") + //fmt.Println("Step 4") verifiedAt := utilities.MakeTimestamp() @@ -126,7 +127,7 @@ func Verify(claim structures.Claim, rule structures.Rule, session structures.Ses rid, err := AddResult(r) // cid a string with the claim ID if err != nil { - return "", structures.NoResult, fmt.Errorf("Error adding result, session %v might still be open: %w", sid, err) + return "", structures.NoResult, fmt.Errorf("Error adding result, session %v might still be open: %v", sid, err) } // Step 7 ****************************************************** @@ -134,7 +135,7 @@ func Verify(claim structures.Claim, rule structures.Rule, session structures.Ses sderr := AddResultToSession(sid, rid) if sderr != nil { - return rid, returnedRV, fmt.Errorf("Error adding result %v to session %v. Claim added, session may be still open: %w", rid, sid, err) + return rid, returnedRV, fmt.Errorf("Error adding result %v to session %v. Claim added, session may be still open: %v", rid, sid, err) } // Step 8 ****************************************************** diff --git a/janeserver/otherconfigfiles/local.yaml b/janeserver/otherconfigfiles/local.yaml deleted file mode 100644 index abd7220..0000000 --- a/janeserver/otherconfigfiles/local.yaml +++ /dev/null @@ -1,32 +0,0 @@ -#Some general naming -system: - name: ASVR_GO_1 - -#MongoDB Configuration -database: - connection: mongodb://127.0.0.1:27017 - name: localasvr - -#MQTT Configuration -messaging: - broker: 127.0.0.1 - port: 1883 - clientid: ASVR_GO_1_LOCAL - -#REST Interface Configuration -rest: - port: 8520 - crt: temporary.crt - key: temporary.key - usehttp: true - -#Web Interface Configuration -web: - port: 8540 - crt: temporary.crt - key: temporary.key - usehttp: true - -#Log file -logfile: - location: /tmp/ga10.log diff --git a/janeserver/otherconfigfiles/nconfig.yaml b/janeserver/otherconfigfiles/nconfig.yaml deleted file mode 100644 index 0bf23a5..0000000 --- a/janeserver/otherconfigfiles/nconfig.yaml +++ /dev/null @@ -1,32 +0,0 @@ -#Some general naming -system: - name: ASVR_GO_1 - -#MongoDB Configuration -database: - connection: mongodb://10.144.176.154:27017 - name: attestation2 - -#MQTT Configuration -messaging: - broker: 10.144.176.154 - port: 1883 - clientid: ASVR_GO_1 - -#REST Interface Configuration -rest: - port: 8520 - crt: temporary.crt - key: temporary.key - usehttp: true - -#Web Interface Configuration -web: - port: 8540 - crt: temporary.crt - key: temporary.key - usehttp: true - -#Log file -logfile: - location: /tmp/ga10.log diff --git a/janeserver/protocols/a10httprestv2/public.go b/janeserver/protocols/a10httprestv2/public.go index 0dcc3f0..dc43935 100644 --- a/janeserver/protocols/a10httprestv2/public.go +++ b/janeserver/protocols/a10httprestv2/public.go @@ -10,7 +10,7 @@ import ( "net/http" "a10/structures" - "a10/utilities" + _ "a10/utilities" ) const nonceSize int = 24 @@ -25,8 +25,8 @@ func Registration() structures.Protocol { // It returns a "json" structure and a string with the body type. // If requestFromTA returns and error, then it is encoded here and returned. // The body type is *ERROR in these situations and the body should have a field "error": -func Call(e structures.Element, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { - rtn, ips, err := requestFromTA(e, p, s, aps) +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { + rtn, ips, err := requestFromTA(e, ep, p, s, aps) if err != nil { rtn["error"] = err.Error() @@ -49,7 +49,7 @@ func mergeMaps(m1 map[string]interface{}, m2 map[string]interface{}) map[string] // This function performs the actual interaction with the TA // This will be highly specific to the actual protocol and its implemented intents -func requestFromTA(e structures.Element, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, error) { +func requestFromTA(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, error) { var empty map[string]interface{} = make(map[string]interface{}) // this is an *instantiated* empty map used for error situations var bodymap map[string]interface{} // this is used to store the result of the final unmarshalling of the body received from the TA @@ -72,12 +72,16 @@ func requestFromTA(e structures.Element, p structures.Intent, s structures.Sessi ips["tpm2/device"] = (e.TPM2).Device } + if p.Function == "tpm2/newpcrs" { + ips["tpm2/device"] = (e.TPM2).Device + } + if p.Function == "tpm2/quote" { ips["tpm2/device"] = (e.TPM2).Device ips["tpm2/akhandle"] = (e.TPM2).AK.Handle nce := make([]byte, nonceSize) _, _ = rand.Read(nce) - ips["tpm2/nonce"] = nce + ips["tpm2/nonce"] = base64.StdEncoding.EncodeToString(nce) } if p.Function == "uefi/eventlog" { @@ -104,7 +108,7 @@ func requestFromTA(e structures.Element, p structures.Intent, s structures.Sessi return empty, cps, fmt.Errorf("JSON Marshalling failed: %w", err) } - url := e.Endpoint + "/" + p.Function + url := ep.Endpoint + "/" + p.Function req, err := http.NewRequest("POST", url, bytes.NewBuffer(postbody)) req.Header.Set("Content-Type", "application/json") client := &http.Client{} @@ -116,12 +120,8 @@ func requestFromTA(e structures.Element, p structures.Intent, s structures.Sessi defer resp.Body.Close() taResponse, _ := io.ReadAll(resp.Body) - fmt.Println("*****************") - fmt.Printf("taReponse is %v", taResponse) err = json.Unmarshal(taResponse, &bodymap) - fmt.Println("bodymap") - fmt.Printf("%v", bodymap) - fmt.Println("*****************") + fmt.Printf("bodymap %v\n", bodymap) if err != nil { return empty, cps, fmt.Errorf("JSON Unmarshalling reponse from TA: %w", err) @@ -131,44 +131,5 @@ func requestFromTA(e structures.Element, p structures.Intent, s structures.Sessi return bodymap, cps, fmt.Errorf("TA reports error %v with response %v", resp.Status, taResponse) } - if p.Function == "tpm2/quote" { - quoteValue, ok := bodymap["quote"] - if !ok { - return bodymap, cps, fmt.Errorf("missing quote data in response") - } - quoteStr, ok := quoteValue.(string) - if !ok { - return bodymap, cps, fmt.Errorf("quote value is not a string") - } - quoteBytes, err := base64.StdEncoding.DecodeString(quoteStr) - if err != nil { - return nil, cps, fmt.Errorf("could not base64 decode quote") - } - - signatureValue, ok := bodymap["signature"] - if !ok { - return bodymap, cps, fmt.Errorf("missing signature data in response") - } - signatureStr, ok := signatureValue.(string) - if !ok { - return bodymap, cps, fmt.Errorf("signature value is not a string") - } - signatureBytes, err := base64.StdEncoding.DecodeString(signatureStr) - if err != nil { - return nil, cps, fmt.Errorf("could not base64 decode signature") - } - - var attestableData utilities.AttestableData - attestableData.Decode(quoteBytes, signatureBytes) - - // Try to parse the quote into a map representation for display purposes - parsed, err := attestableData.Parse() - if err != nil { - return bodymap, cps, err - } - bodymap["parsed"] = parsed - - } - return bodymap, cps, nil } diff --git a/janeserver/protocols/marblerun/public.go b/janeserver/protocols/marblerun/public.go index 6636c38..acbf73a 100644 --- a/janeserver/protocols/marblerun/public.go +++ b/janeserver/protocols/marblerun/public.go @@ -25,8 +25,8 @@ func Registration() structures.Protocol { return structures.Protocol{"A10MARBLERUNPROTOCOL", "Protocol to generate quote from MarbleRun", Call, intents} } -func Call(e structures.Element, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { - rtn, cps, err := requestFromMarbleRun(e, p, s, aps) +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { + rtn, cps, err := requestFromMarbleRun(e, ep, p, s, aps) if err != nil { rtn["error"] = err.Error() @@ -74,7 +74,7 @@ func coordinatorTLSConfig(certs []string) (*tls.Config, error) { return &conf, nil } -func requestFromMarbleRun(e structures.Element, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, error) { +func requestFromMarbleRun(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, error) { var empty map[string]interface{} = make(map[string]interface{}) // this is an *instantiated* empty map used for error situations var bodymap map[string]interface{} // this is used to store the result of the final unmarshalling of the body received from the TA @@ -93,7 +93,7 @@ func requestFromMarbleRun(e structures.Element, p structures.Intent, s structure return empty, nil, fmt.Errorf("intent not supported %s", p.Function) } - url := e.Endpoint + "/" + suffix + url := ep.Endpoint + "/" + suffix var tr http.Transport // If we don't have setup any certs and are doing a quote ignore the TLS config for now if p.Function == quoteIntent && len(e.MRCoordinator.Certs) == 0 { diff --git a/janeserver/protocols/netconfprotocol/public.go b/janeserver/protocols/netconfprotocol/public.go index a4c59d9..5dcd5f6 100644 --- a/janeserver/protocols/netconfprotocol/public.go +++ b/janeserver/protocols/netconfprotocol/public.go @@ -16,13 +16,13 @@ func Registration() structures.Protocol { return structures.Protocol{"A10NETCONF", "POC protocol module for NetConf", Call, intents} } -func Call(e structures.Element, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { // Create a test body rtn := map[string]interface{}{ "foo": "bar", - "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", e.Protocol, p.Function), + "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", ep.Protocol, p.Function), "aNumber": 42, } diff --git a/janeserver/protocols/nullprotocol/public.go b/janeserver/protocols/nullprotocol/public.go index 0a85842..930ebc9 100644 --- a/janeserver/protocols/nullprotocol/public.go +++ b/janeserver/protocols/nullprotocol/public.go @@ -16,13 +16,13 @@ func Registration() structures.Protocol { return structures.Protocol{"A10NULLPROTOCOL", "Testing protocol, always returns a test claim", Call, intents} } -func Call(e structures.Element, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { // Create a test body rtn := map[string]interface{}{ "foo": "bar", - "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", e.Protocol, p.Function), + "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", ep.Protocol, p.Function), "aNumber": 42, } diff --git a/janeserver/protocols/ratsdprotocol/public.go b/janeserver/protocols/ratsdprotocol/public.go new file mode 100644 index 0000000..3cbcb34 --- /dev/null +++ b/janeserver/protocols/ratsdprotocol/public.go @@ -0,0 +1,132 @@ +package ratsdprotocol + +import ( + "bytes" + "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "net/http" + "reflect" + "strings" + + "a10/structures" + //"a10/utilities" +) + +const nonceSize int = 64 + +func Registration() structures.Protocol { + intents := []string{"ratsd/chares"} + + return structures.Protocol{"RATSD", "RATSD protcol for ratsd", Call, intents} +} + +// THis is the function that is called by operations.attestation --- this is the entry point to the actual protocol part. +// It returns a "json" structure and a string with the body type. +// If requestFromTA returns and error, then it is encoded here and returned. +// The body type is *ERROR in these situations and the body should have a field "error": +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { + rtn, ips, err := requestFromRATSD(e, ep, p, s, aps) + + if err != nil { + rtn["error"] = err.Error() + return rtn, ips, structures.CLAIMERROR + } else { + return rtn, ips, p.Function + } +} + +func mergeMaps(m1 map[string]interface{}, m2 map[string]interface{}) map[string]interface{} { + merged := make(map[string]interface{}) + for k, v := range m1 { + merged[k] = v + } + for key, value := range m2 { + merged[key] = value + } + return merged +} + +// This function performs the actual interaction with ratsd +// This will be highly specific to the actual protocol and its implemented intents +func requestFromRATSD(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, aps map[string]interface{}) (map[string]interface{}, map[string]interface{}, error) { + + var empty map[string]interface{} = make(map[string]interface{}) // this is an *instantiated* empty map used for error situations + var bodymap map[string]interface{} = make(map[string]interface{}) // this is used to store the result of the final unmarshalling of the body received from the TA + + // Parameters + // + // Some come from the element itself, eg: UEFI.eventlog + // Then those supplied by the policy and finally the additional parameters + // Only certain intents supply parameters and these are dealt with on a case by case basis here + // + // First we construct "ips" which is the intial set of parameters + // + // For sanity reasons (and Go's strong typing, the parameters is a plain key,value list) + var ips map[string]interface{} = make(map[string]interface{}) + + // create None for RATSD call + nce := make([]byte, nonceSize) + _, _ = rand.Read(nce) + ips["nonce"] = base64.URLEncoding.EncodeToString(nce) + ips["nonce"] = strings.TrimRight(ips["nonce"].(string), "=") + fmt.Printf("Nonce is %v\n", ips["nonce"]) + + // merge ips with policy parameters. The policy parameters take precidence + + pps := mergeMaps(ips, p.Parameters) + cps := mergeMaps(pps, aps) // this is the final set of call parameters and should be returned to be part of the claim + + // Construct the call + + postbody, err := json.Marshal(cps) + if err != nil { + return empty, cps, fmt.Errorf("JSON Marshalling failed: %w", err) + } + + url := ep.Endpoint + "/" + p.Function + req, err := http.NewRequest("POST", url, bytes.NewBuffer(postbody)) + req.Header.Set("Content-Type", "application/vnd.veraison.chares+json") + req.Header.Set("Accept", "application/eat-ucs+json; eat_profile=\"tag:github.com,2024:veraison/ratsd\"") + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return empty, cps, err // err will be the error from http.client.Do + } + defer resp.Body.Close() + + taResponse, _ := io.ReadAll(resp.Body) + fmt.Println("*****************") + fmt.Printf("ratsd reponse is %v type is %v", taResponse, reflect.TypeOf(taResponse)) + + var asciiString string + for _, code := range taResponse { + asciiString += string(rune(code)) + } + fmt.Printf("as ascii %v\n", asciiString) + + bodymap["response"] = asciiString + + // at the moment we just get a string of integers back + //err = json.Unmarshal(taResponse, &bodymap) + fmt.Println("\nbodymap") + fmt.Printf("%v", bodymap) + fmt.Println("*****************") + + if err != nil { + return empty, cps, fmt.Errorf("JSON Unmarshalling reponse from TA: %w", err) + } + + switch resp.Status { + case "200 OK": + return bodymap, cps, nil + + default: + return bodymap, cps, fmt.Errorf("RATSD reports error %v with response %v", resp.Status, taResponse) + } + +} diff --git a/janeserver/protocols/registerProtocols.go b/janeserver/protocols/registerProtocols.go index c4b4fdd..938bfb1 100644 --- a/janeserver/protocols/registerProtocols.go +++ b/janeserver/protocols/registerProtocols.go @@ -7,6 +7,7 @@ import ( "a10/protocols/marblerun" "a10/protocols/netconfprotocol" "a10/protocols/nullprotocol" + "a10/protocols/ratsdprotocol" "a10/protocols/testcontainerprotocol" "a10/protocols/veraisonpsaprotocol" ) @@ -18,5 +19,6 @@ func RegisterProtocols() { operations.AddProtocol(marblerun.Registration()) operations.AddProtocol(testcontainerprotocol.Registration()) operations.AddProtocol(veraisonpsaprotocol.Registration()) + operations.AddProtocol(ratsdprotocol.Registration()) } diff --git a/janeserver/protocols/testcontainerprotocol/public.go b/janeserver/protocols/testcontainerprotocol/public.go index aebe7df..ddc8d84 100644 --- a/janeserver/protocols/testcontainerprotocol/public.go +++ b/janeserver/protocols/testcontainerprotocol/public.go @@ -15,7 +15,7 @@ func Registration() structures.Protocol { return structures.Protocol{"TESTCONTAINERPROTOCOL", "Test protocol for containers", Call, intents} } -func Call(e structures.Element, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { // Create a test body @@ -39,7 +39,7 @@ func Call(e structures.Element, p structures.Intent, s structures.Session, cps m rtn := map[string]interface{}{ "foo": "bar", - "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", e.Protocol, p.Function), + "calling": fmt.Sprintf("with protocol %v I would send an intent to %v", ep.Protocol, p.Function), "aNumber": 42, } diff --git a/janeserver/protocols/veraisonpsaprotocol/public.go b/janeserver/protocols/veraisonpsaprotocol/public.go index 9283775..e46d006 100644 --- a/janeserver/protocols/veraisonpsaprotocol/public.go +++ b/janeserver/protocols/veraisonpsaprotocol/public.go @@ -16,7 +16,7 @@ func Registration() structures.Protocol { return structures.Protocol{"EVCLI_PSA", "EVCLI Protocol - TEST VERSION, always returns a PSA test claim", Call, intents} } -func Call(e structures.Element, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { +func Call(e structures.Element, ep structures.Endpoint, p structures.Intent, s structures.Session, cps map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) { // Create a test body diff --git a/janeserver/rules/keylime/public.go b/janeserver/rules/keylime/public.go index 35ece9a..6899995 100644 --- a/janeserver/rules/keylime/public.go +++ b/janeserver/rules/keylime/public.go @@ -218,7 +218,7 @@ func ValidateIMA(claim structures.Claim, rule string, ev structures.ExpectedValu resp, err := postIMARequest(req) if err != nil { - return structures.Fail, fmt.Sprintf("Communication with Keylime failed %w", err), nil + return structures.Fail, fmt.Sprintf("Communication with Keylime failed %v", err.Error()), nil } if resp.Failure != "" { diff --git a/janeserver/rules/marblerun/public.go b/janeserver/rules/marblerun/public.go index cb43ad1..664561a 100644 --- a/janeserver/rules/marblerun/public.go +++ b/janeserver/rules/marblerun/public.go @@ -64,7 +64,7 @@ func ValidateCoordinator(claim structures.Claim, rule string, ev structures.Expe // Validate the report itself. Requires access to PCCS report, err := eclient.VerifyRemoteReport(reportBytes) if err != nil { - return structures.Fail, fmt.Sprintf("verification of report failed %w", err), nil + return structures.Fail, fmt.Sprintf("verification of report failed %v", err.Error()), nil } caCertRaw := certs[len(certs)-1].Bytes @@ -247,7 +247,7 @@ func ValidatePackage(claim structures.Claim, rule string, ev structures.Expected } func ValidateMarble(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { - log.Printf("parameters", parameter) + log.Printf("parameters %v", parameter) marbleName, ok := parameter["marble"] if !ok { return structures.MissingExpectedValue, "No marble specified in parameter", nil diff --git a/janeserver/rules/sysrules/public.go b/janeserver/rules/sysrules/public.go index 63c5dc7..8b2f9fd 100644 --- a/janeserver/rules/sysrules/public.go +++ b/janeserver/rules/sysrules/public.go @@ -2,13 +2,17 @@ package sysrules import ( "a10/structures" + "fmt" + "strings" ) func Registration() []structures.Rule { - ruleS := structures.Rule{"sys_taRunningSafely", "Checks the the TA is NOT in unsafe mode of operation", Callrulesafe, false} + ruleS := structures.Rule{"sys_taRunningSafely", "Checks that the TA is NOT in unsafe mode of operation", Callrulesafe, false} + ruleMTA := structures.Rule{"sys_machineID_Agent", "Checks that the Machine ID in /etc/machineid has not been changed - obtained from trust agent", CallrulemachineIDTA, true} + ruleMCR := structures.Rule{"sys_machineID_CrossRef", "Checks that the Machine ID in /etc/machineid has not been changed - cross-referenced from Element description", CallrulemachineIDCR, false} - return []structures.Rule{ruleS} + return []structures.Rule{ruleS, ruleMTA, ruleMCR} } func Callrulesafe(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { @@ -24,3 +28,54 @@ func Callrulesafe(claim structures.Claim, rule string, ev structures.ExpectedVal return structures.Success, "TA operating in safe mode", nil } } + +func CallrulemachineIDTA(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { + + // NB: there's a lot of trimming of strings going on here, this is because we want to drop any newline etc + // characters, just in case. Tarzan however does now strip these, but done here as an addition precaution + // because reading /etc/machineid as tarzan does introduce these characters, even though they are not + // present in the original file. + + machineid, ok := claim.Body["machineid"] + if !ok { + return structures.RuleCallFailure, "TA not of correct type, or not reporting machineid parameter value", nil + } + claimedMachineID := strings.Trim(fmt.Sprintf("%v", machineid), " \t\n") + + emachineid := ((ev.EVS)["machineid"]).(string) + expectedMachineID := strings.Trim(fmt.Sprintf("%v", emachineid), " \t\n") + + // and now the check + if expectedMachineID == claimedMachineID { + return structures.Success, "MachineID matches", nil + } else { + msg := fmt.Sprintf("Got %v as Machine ID version but expected %v", claimedMachineID, expectedMachineID) + return structures.Fail, msg, nil + } + +} + +func CallrulemachineIDCR(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { + + machineid, ok := claim.Body["machineid"] + if !ok { + return structures.RuleCallFailure, "TA not of correct type, or not reporting machineid parameter value", nil + } + + claimedMachineID := strings.Trim(fmt.Sprintf("%v", machineid), " \t\n") + + // We get this from the CLAIM.ELEMENT.HOST.MACHINEID + expectedMachineID := claim.Header.Element.Host.MachineID + fmt.Printf("Claim machine ID is %v\n", expectedMachineID) + + fmt.Printf("Comparison\n%v\n%v\n%v\n===\n", claimedMachineID, expectedMachineID, claimedMachineID == expectedMachineID) + + // and now the check + if expectedMachineID == claimedMachineID { + return structures.Success, "MachineID matches", nil + } else { + msg := fmt.Sprintf("Got %v as Machine ID version but expected %v", claimedMachineID, expectedMachineID) + return structures.Fail, msg, nil + } + +} diff --git a/janeserver/rules/tpm2rules/public.go b/janeserver/rules/tpm2rules/public.go index 7d3aca6..2a35665 100644 --- a/janeserver/rules/tpm2rules/public.go +++ b/janeserver/rules/tpm2rules/public.go @@ -1,34 +1,25 @@ package tpm2rules import ( - "bytes" - "crypto/sha256" - "encoding/base64" - "encoding/hex" "fmt" - "reflect" - "slices" - "strconv" - "a10/operations" "a10/structures" - "a10/utilities" - - "go.mongodb.org/mongo-driver/bson/primitive" + "github.com/mitchellh/mapstructure" // from Hasicorp https://stackoverflow.com/questions/26744873/converting-map-to-struct ) func Registration() []structures.Rule { attestedPCRDigest := structures.Rule{"tpm2_attestedValue", "Checks the TPM's reported attested value against the expected value", AttestedPCRDigest, true} - checkPCRSelection := structures.Rule{"tpm2_PCRSelection", "Checks if a quote includes the correct PCRs", checkPCRSelection, true} - checkQuoteDigest256 := structures.Rule{"tpm2_quoteDigest256", "Checks if a claim of PCRs match the hash in the quote (sha256)", checkQuoteDigest256, false} + //checkPCRSelection := structures.Rule{"tpm2_PCRSelection", "Checks if a quote includes the correct PCRs", checkPCRSelection, true} + //checkQuoteDigest256 := structures.Rule{"tpm2_quoteDigest256", "Checks if a claim of PCRs match the hash in the quote (sha256)", checkQuoteDigest256, false} ruleFirmware := structures.Rule{"tpm2_firmware", "Checks the TPM firmware version against the expected value", FirmwareRule, true} ruleMagic := structures.Rule{"tpm2_magicNumber", "Checks the quote magic number is 0xFF544347", MagicNumberRule, false} + ruleQuoteType := structures.Rule{"tpm2_type", "Checks the type of the quote which must be 0x8018", QuoteTypeRule, false} ruleIsSafe := structures.Rule{"tpm2_safe", "Checks that the value of safe is 1", IsSafe, false} - ruleValidSignature := structures.Rule{"tpm2_validSignature", "Checks that the signature of rule is valid against the signing attestation key", ValidSignature, false} + //ruleValidSignature := structures.Rule{"tpm2_validSignature", "Checks that the signature of rule is valid against the signing attestation key", ValidSignature, false} ruleValidNonce := structures.Rule{"tpm2_validNonce", "Checks that nonce used for the claim matches the nonce in the quote", ValidNonce, false} - return []structures.Rule{ruleFirmware, ruleMagic, attestedPCRDigest, ruleIsSafe, ruleValidSignature, ruleValidNonce, checkQuoteDigest256, checkPCRSelection} + return []structures.Rule{ruleFirmware, ruleMagic, attestedPCRDigest, ruleIsSafe, ruleValidNonce, ruleQuoteType} } func IsSafe(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { @@ -37,11 +28,13 @@ func IsSafe(claim structures.Claim, rule string, ev structures.ExpectedValue, se return structures.Fail, "Parsing TPM quote failed", err } - if !q.Data.ClockInfo.Safe { - return structures.Fail, "Uncommanded device/TPM shutdown", nil + msg := fmt.Sprintf("TPM safe value is %v", q.ClockInfo.Safe) + + if q.ClockInfo.Safe == "false" { + return structures.Fail, "Uncommanded device/TPM shutdown. " + msg, nil } - return structures.Success, "", nil + return structures.Success, "TPM shutdown normal. " + msg, nil } func AttestedPCRDigest(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { @@ -50,11 +43,7 @@ func AttestedPCRDigest(claim structures.Claim, rule string, ev structures.Expect return structures.Fail, "Parsing TPM quote failed", err } - quoteData, err := q.Data.Attested.Quote() - if err != nil { - return structures.Fail, "Parsing TPM quote from Attested failed", err - } - claimedAV := hex.EncodeToString(quoteData.PCRDigest.Buffer) + claimedAV := q.Attested.PCRDigest expectedAV := (ev.EVS)["attestedValue"] if expectedAV == claimedAV { @@ -63,20 +52,20 @@ func AttestedPCRDigest(claim structures.Claim, rule string, ev structures.Expect msg := fmt.Sprintf("Got %v as attested value but expected %v", claimedAV, expectedAV) return structures.Fail, msg, nil } - } func FirmwareRule(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { q, err := getQuote(claim) + if err != nil { return structures.Fail, "Parsing TPM quote failed", err } - claimedFirmware := fmt.Sprintf("%d", q.Data.FirmwareVersion) + claimedFirmware := fmt.Sprintf("%v", q.FirmwareVersion) expectedFirmware := (ev.EVS)["firmwareVersion"] if expectedFirmware == claimedFirmware { - return structures.Success, "", nil + return structures.Success, "Firmware version matches", nil } else { msg := fmt.Sprintf("Got %v as firmware version but expected %v", claimedFirmware, expectedFirmware) return structures.Fail, msg, nil @@ -90,173 +79,183 @@ func MagicNumberRule(claim structures.Claim, rule string, ev structures.Expected return structures.Fail, "Parsing TPM quote failed", err } - if err := q.Data.Magic.Check(); err != nil { - return structures.Fail, "TPM magic number and/or TPMS_ATTEST type wrong", nil + if q.Magic != "ff544347" { + msg := fmt.Sprintf("TPM Quote (TPMS_ATTEST) type value is wrong - probably not a quote - received %v, expected ff544347", q.Magic) + return structures.Fail, msg, nil } return structures.Success, "", nil } -func ValidSignature(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { - quote, err := getQuote(claim) +func QuoteTypeRule(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { + q, err := getQuote(claim) if err != nil { return structures.Fail, "Parsing TPM quote failed", err } - akBytes, err := base64.StdEncoding.DecodeString(claim.Header.Element.TPM2.AK.Public) - if err != nil { - return structures.RuleCallFailure, "Base64 decoding the AK failed", err - } - akKey, err := utilities.ParseTPMKey(akBytes) - if err != nil { - return structures.Fail, "Parsing AK failed", err - } - - if err := quote.VerifySignature(akKey); err != nil { - return structures.Fail, "Validation of the quote failed", nil + if q.Type != "8018" { + msg := fmt.Sprintf("TPM Quote (TPMS_ATTEST) type value is wrong - probably not a quote - received %v, expected 8018", q.Type) + return structures.Fail, msg, nil } - return structures.Success, "Quote was validated successfully", nil + return structures.Success, "TPM Quote (TPMS_ATTEST) type value is correct", nil } -func ValidNonce(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { - quote, err := getQuote(claim) - if err != nil { - return structures.Fail, "Parsing TPM quote failed", err - } - quoteNonceBytes := quote.Data.ExtraData.Buffer +// func ValidSignature(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { +// quote, err := getQuote(claim) +// if err != nil { +// return structures.Fail, "Parsing TPM quote failed", err +// } - claimNonceValue, ok := claim.Header.CallParameters["tpm2/nonce"] - if !ok { - return structures.RuleCallFailure, "claim has no nonce", nil - } - claimNonceBytes, ok := claimNonceValue.(primitive.Binary) - if !ok { - return structures.RuleCallFailure, fmt.Sprintf("Nonce is not of type Binary. It is: %s", reflect.TypeOf(claimNonceValue)), nil - } +// akBytes, err := base64.StdEncoding.DecodeString(claim.Header.Element.TPM2.AK.Public) +// if err != nil { +// return structures.RuleCallFailure, "Base64 decoding the AK failed", err +// } +// akKey, err := utilities.ParseTPMKey(akBytes) +// if err != nil { +// return structures.Fail, "Parsing AK failed", err +// } - if !bytes.Equal(quoteNonceBytes, claimNonceBytes.Data) { - return structures.Fail, fmt.Sprintf("Nonce are not matching, got: \"%s\", expected: \"%s\"", hex.EncodeToString(quoteNonceBytes), hex.EncodeToString(claimNonceBytes.Data)), nil - } +// if err := quote.VerifySignature(akKey); err != nil { +// return structures.Fail, "Validation of the quote failed", nil +// } - return structures.Success, "nonce matches", nil -} +// return structures.Success, "Quote was validated successfully", nil +// } -func checkPCRSelection(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { +func ValidNonce(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { quote, err := getQuote(claim) if err != nil { return structures.Fail, "Parsing TPM quote failed", err } + quoteNonceValue := quote.ExtraData - data, err := quote.Data.Attested.Quote() - if err != nil { - return structures.Fail, "Parsing Attest structure into Quote failed", err - } - selection := utilities.TPMSPCRSelectionToList(data.PCRSelect.PCRSelections) - - evSelection, ok := ev.EVS["pcrselection"] - if !ok { - return structures.MissingExpectedValue, "pcrselection not given", err - } - var evSelectionList []int - for _, v := range evSelection.(primitive.A) { - index, err := strconv.Atoi(v.(string)) - if err != nil { - return structures.Fail, "pcrselection contains non integer strings", err - } - evSelectionList = append(evSelectionList, index) - } - if len(evSelectionList) != len(selection) { - return structures.Fail, "not the same length", err - } - for _, v := range evSelectionList { - if !slices.Contains(selection, v) { - return structures.Fail, fmt.Sprintf("Index %d is missing in quote", v), err - } - } - return structures.Success, "", err -} + claimNonceValue := fmt.Sprintf("%s", claim.Header.CallParameters["tpm2/nonce"]) -func checkQuoteDigest256(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { - quote, err := getQuote(claim) - if err != nil { - return structures.Fail, "Parsing TPM quote failed", err + if claimNonceValue != quoteNonceValue { + return structures.Fail, fmt.Sprintf("Nonce are not matching, got: %v, expected: %v", quoteNonceValue, claimNonceValue), nil } - pcrsClaimID := parameter["pcrscid"].(string) - pcrsClaim, err := operations.GetClaimByItemID(pcrsClaimID) - if err != nil { - return structures.Fail, "Could not get PCRs claim", err - } + msg := fmt.Sprintf("Nonce matches: (base64) %v", quoteNonceValue) + return structures.Success, msg, nil +} - data, err := quote.Data.Attested.Quote() - if err != nil { - return structures.Fail, "Parsing Attest structure into Quote failed", err - } - digest := data.PCRDigest.Buffer - selection := utilities.TPMSPCRSelectionToList(data.PCRSelect.PCRSelections) +// func checkPCRSelection(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { +// quote, err := getQuote(claim) +// if err != nil { +// return structures.Fail, "Parsing TPM quote failed", err +// } + +// pcrdigest := quote.Attested.PCRDigest +// if err != nil { +// return structures.Fail, "Parsing Attest structure into Quote failed", err +// } +// selection := utilities.TPMSPCRSelectionToList(data.PCRSelect.PCRSelections) + +// evSelection, ok := ev.EVS["pcrselection"] +// if !ok { +// return structures.MissingExpectedValue, "pcrselection not given", err +// } +// var evSelectionList []int +// for _, v := range evSelection.(primitive.A) { +// index, err := strconv.Atoi(v.(string)) +// if err != nil { +// return structures.Fail, "pcrselection contains non integer strings", err +// } +// evSelectionList = append(evSelectionList, index) +// } +// if len(evSelectionList) != len(selection) { +// return structures.Fail, "not the same length", err +// } +// for _, v := range evSelectionList { +// if !slices.Contains(selection, v) { +// return structures.Fail, fmt.Sprintf("Index %d is missing in quote", v), err +// } +// } +// return structures.Success, "", err +// } + +// func checkQuoteDigest256(claim structures.Claim, rule string, ev structures.ExpectedValue, session structures.Session, parameter map[string]interface{}) (structures.ResultValue, string, error) { +// quote, err := getQuote(claim) +// if err != nil { +// return structures.Fail, "Parsing TPM quote failed", err +// } +// pcrsClaimID := parameter["pcrscid"].(string) + +// pcrsClaim, err := operations.GetClaimByItemID(pcrsClaimID) +// if err != nil { +// return structures.Fail, "Could not get PCRs claim", err +// } + +// data, err := quote.Attested.Quote() +// if err != nil { +// return structures.Fail, "Parsing Attest structure into Quote failed", err +// } +// digest := data.PCRDigest.Buffer +// selection := utilities.TPMSPCRSelectionToList(data.PCRSelect.PCRSelections) + +// sha256Entries := make(map[string]string) +// for k, v := range pcrsClaim.Body["sha256"].(map[string]interface{}) { +// sha256Entries[k] = v.(string) +// } + +// hash := sha256.New() +// for _, pcrIndex := range selection { +// pcrIndexS := fmt.Sprintf("%d", pcrIndex) + +// entry, ok := sha256Entries[pcrIndexS] +// if !ok { +// return structures.Fail, fmt.Sprintf("PCR index missing in PCR claim: %s", entry), err +// } +// entryBytes, err := hex.DecodeString(entry) +// if err != nil { +// return structures.Fail, "Entry not valid hex", err +// } +// hash.Write(entryBytes) +// } + +// digestPCRs := hash.Sum([]byte{}) +// if !bytes.Equal(digestPCRs, digest) { +// return structures.Fail, "PCRs and hash in quote do not match", err +// } + +// return structures.Success, "PCRs and hash in quote match", err +// } - sha256Entries := make(map[string]string) - for k, v := range pcrsClaim.Body["sha256"].(map[string]interface{}) { - sha256Entries[k] = v.(string) - } +// Constructs AttestableData struct with signature +// TODO find way to cache this in the session object - hash := sha256.New() - for _, pcrIndex := range selection { - pcrIndexS := fmt.Sprintf("%d", pcrIndex) - - entry, ok := sha256Entries[pcrIndexS] - if !ok { - return structures.Fail, fmt.Sprintf("PCR index missing in PCR claim: %s", entry), err - } - entryBytes, err := hex.DecodeString(entry) - if err != nil { - return structures.Fail, "Entry not valid hex", err - } - hash.Write(entryBytes) - } +type clockInfo struct { + Clock string `json:"clock"` + ResetCount string `json:"resetcount"` + RestartCount string `json:"restartcount"` + Safe string `json:"safe"` +} - digestPCRs := hash.Sum([]byte{}) - if !bytes.Equal(digestPCRs, digest) { - return structures.Fail, "PCRs and hash in quote do not match", err - } +type attested struct { + PCRSelect string `json:"pcrselect"` + PCRDigest string `json:"pcrdigest"` +} - return structures.Success, "PCRs and hash in quote match", err +type quoteStructure struct { + Magic string `json:"magic"` + Type string `json:"type"` + QualifiedSigner string `json:"qualifiedsigner"` + ExtraData string `json:"extradata"` + ClockInfo clockInfo `json:"clockinfo"` + FirmwareVersion string `json:"firmwareVersion"` + Attested attested `json:"attested"` } -// Constructs AttestableData struct with signature -// TODO find way to cache this in the session object -func getQuote(claim structures.Claim) (*utilities.AttestableData, error) { +func getQuote(claim structures.Claim) (quoteStructure, error) { quoteData, ok := (claim.Body)["quote"] + //fmt.Printf("\n### GetQuote %v\n%v\n%v\n\n", reflect.TypeOf(quoteData), ok, quoteData) if !ok { - return nil, fmt.Errorf("claim does not contain quote") - - } - quoteStr := quoteData.(string) - quoteBytes, err := base64.StdEncoding.DecodeString(quoteStr) - if err != nil { - return nil, fmt.Errorf("could not base64 decode quote") - } - var signatureBytes []byte - signatureData, ok := (claim.Body)["signature"] - if !ok { - return nil, fmt.Errorf("claim does not contain a signature") - } - signatureStr := signatureData.(string) - signatureBytes, err = base64.StdEncoding.DecodeString(signatureStr) - if err != nil { - return nil, fmt.Errorf("could not base64 decode signature") - } - - var quote utilities.AttestableData - err = quote.Decode(quoteBytes, signatureBytes) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal TPM structures %w", err) - } + return quoteStructure{}, fmt.Errorf("claim does not contain quote") - if !quote.IsQuote() { - return nil, fmt.Errorf("attestable data is not quote") } - return "e, nil + var qs quoteStructure + mapstructure.Decode(quoteData, &qs) + return qs, nil } diff --git a/janeserver/services/restapi/endpointsAttestVerify.go b/janeserver/services/restapi/endpointsAttestVerify.go index d96b699..cb50f19 100644 --- a/janeserver/services/restapi/endpointsAttestVerify.go +++ b/janeserver/services/restapi/endpointsAttestVerify.go @@ -23,16 +23,17 @@ type postVerifyReturn struct { type attestStr struct { EID string `json:"eid"` + EPN string `json:"epn"` PID string `json:"pid"` SID string `json:"sid"` - Parameters map[string]interface{} `json:"parameters",bson:"parameters"` + Parameters map[string]interface{} `json:"parameters" bson:"parameters"` } type verifyStr struct { CID string `json:"cid"` Rule string `json:"rule"` SID string `json:"sid"` - Parameters map[string]interface{} `json:"parameters",bson:"parameters"` + Parameters map[string]interface{} `json:"parameters" bson:"parameters"` } func postAttest(c echo.Context) error { @@ -42,33 +43,39 @@ func postAttest(c echo.Context) error { return c.JSON(http.StatusBadRequest, clienterr) } + fmt.Printf("\n attstr is ###%v###", att) + eid := (*att).EID + epn := (*att).EPN pid := (*att).PID sid := (*att).SID element, err := operations.GetElementByItemID(eid) if err != nil { - fmt.Errorf("Element not found: %v", err) + clienterr := postAttestReturn{"", "Element " + eid + " not found"} + return FormattedResponse(c, http.StatusBadRequest, clienterr) } intent, err := operations.GetIntentByItemID(pid) if err != nil { - fmt.Errorf("Intent not found: %v", err) + clienterr := postAttestReturn{"", "Intent " + pid + " not found"} + return FormattedResponse(c, http.StatusBadRequest, clienterr) } session, err := operations.GetSessionByItemID(sid) if err != nil { - fmt.Errorf("Session not found: %v", err) + clienterr := postAttestReturn{"", "Session " + sid + " not found"} + return FormattedResponse(c, http.StatusBadRequest, clienterr) } - res, err := operations.Attest(element, intent, session, (*att).Parameters) + res, err := operations.Attest(element, epn, intent, session, (*att).Parameters) if err != nil { response := postAttestReturn{res, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { response := postAttestReturn{res, ""} - return c.JSON(http.StatusAccepted, response) + return FormattedResponse(c, http.StatusAccepted, response) } } @@ -77,7 +84,7 @@ func postVerify(c echo.Context) error { att := new(verifyStr) if err := c.Bind(att); err != nil { clienterr := postVerifyReturn{"", structures.VerifyCallFailure, err.Error()} - return c.JSON(http.StatusBadRequest, clienterr) + return FormattedResponse(c, http.StatusBadRequest, clienterr) } cid := (*att).CID @@ -104,10 +111,10 @@ func postVerify(c echo.Context) error { if err != nil { response := postVerifyReturn{res, rv, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { response := postVerifyReturn{res, rv, ""} - return c.JSON(http.StatusAccepted, response) + return FormattedResponse(c, http.StatusAccepted, response) } } diff --git a/janeserver/services/restapi/endpointsClaims.go b/janeserver/services/restapi/endpointsClaims.go index 7b577a2..d680eb5 100644 --- a/janeserver/services/restapi/endpointsClaims.go +++ b/janeserver/services/restapi/endpointsClaims.go @@ -23,7 +23,7 @@ func getClaims(c echo.Context) error { if err != nil { log.Println("err=", err) - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { //Convert elems from []structures.ID into a []string var claims_str []string @@ -34,7 +34,7 @@ func getClaims(c echo.Context) error { //Marshall into JSON claims_struct := returnClaims{claims_str, len(claims_str)} - return c.JSON(http.StatusOK, claims_struct) + return FormattedResponse(c, http.StatusOK, claims_struct) } } @@ -43,9 +43,9 @@ func getClaim(c echo.Context) error { claim, err := operations.GetClaimByItemID(itemid) if err != nil { - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { - return c.JSON(http.StatusOK, claim) + return FormattedResponse(c, http.StatusOK, claim) } } @@ -62,7 +62,7 @@ func getClaimsByElementID(c echo.Context) error { if err != nil { log.Println("err=", err) - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { //Convert elems from []structures.ID into a []string var claims_str []string @@ -73,7 +73,7 @@ func getClaimsByElementID(c echo.Context) error { //Marshall into JSON claims_struct := returnClaims{claims_str, len(claims_str)} - return c.JSON(http.StatusOK, claims_struct) + return FormattedResponse(c, http.StatusOK, claims_struct) } } @@ -87,16 +87,16 @@ func postClaim(c echo.Context) error { if err := c.Bind(elem); err != nil { clienterr := postClaimReturn{"", err.Error()} - return c.JSON(http.StatusBadRequest, clienterr) + return FormattedResponse(c, http.StatusBadRequest, clienterr) } res, err := operations.AddClaim(*elem) if err != nil { response := postElementReturn{res, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { response := postElementReturn{res, ""} - return c.JSON(http.StatusCreated, response) + return FormattedResponse(c, http.StatusCreated, response) } } diff --git a/janeserver/services/restapi/endpointsElements.go b/janeserver/services/restapi/endpointsElements.go index 17e454e..1e2ea0e 100644 --- a/janeserver/services/restapi/endpointsElements.go +++ b/janeserver/services/restapi/endpointsElements.go @@ -1,6 +1,7 @@ package restapi import ( + // "fmt" "log" "net/http" @@ -20,7 +21,7 @@ func getElements(c echo.Context) error { if err != nil { log.Println("err=", err) - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { //Convert elems from []structures.ID into a []string var elems_str []string @@ -31,7 +32,7 @@ func getElements(c echo.Context) error { //Marshall into JSON elems_struct := returnElements{elems_str, len(elems_str)} - return c.JSON(http.StatusOK, elems_struct) + return FormattedResponse(c, http.StatusOK, elems_struct) } } @@ -42,9 +43,9 @@ func getElement(c echo.Context) error { if err != nil { log.Println("err=", err) - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { - return c.JSON(http.StatusOK, elem) + return FormattedResponse(c, http.StatusOK, elem) } } @@ -55,7 +56,7 @@ func getElementsByName(c echo.Context) error { if err != nil { log.Println("err=", err) - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { //Convert elems from []structures.ID into a []string var elems_str []string @@ -66,7 +67,29 @@ func getElementsByName(c echo.Context) error { //Marshall into JSON elems_struct := returnElements{elems_str, len(elems_str)} - return c.JSON(http.StatusOK, elems_struct) + return FormattedResponse(c, http.StatusOK, elems_struct) + } +} + +func getElementsByTag(c echo.Context) error { + tag := c.Param("tag") + + elems, err := operations.GetElementsByTag(tag) + + if err != nil { + log.Println("err=", err) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) + } else { + //Convert elems from []structures.ID into a []string + var elems_str []string + for _, e := range elems { + elems_str = append(elems_str, e.ItemID) + } + + //Marshall into JSON + elems_struct := returnElements{elems_str, len(elems_str)} + + return FormattedResponse(c, http.StatusOK, elems_struct) } } @@ -80,17 +103,17 @@ func postElement(c echo.Context) error { if err := c.Bind(elem); err != nil { clienterr := postElementReturn{"", err.Error()} - return c.JSON(http.StatusBadRequest, clienterr) + return FormattedResponse(c, http.StatusBadRequest, clienterr) } res, err := operations.AddElement(*elem) if err != nil { response := postElementReturn{res, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { response := postElementReturn{res, ""} - return c.JSON(http.StatusCreated, response) + return FormattedResponse(c, http.StatusCreated, response) } } @@ -99,12 +122,12 @@ func putElement(c echo.Context) error { if err := c.Bind(elem); err != nil { clienterr := postElementReturn{"", err.Error()} - return c.JSON(http.StatusBadRequest, clienterr) + return FormattedResponse(c, http.StatusBadRequest, clienterr) } if _, err := operations.GetElementByItemID(elem.ItemID); err != nil { response := postElementReturn{"", err.Error()} - return c.JSON(http.StatusNotFound, response) + return FormattedResponse(c, http.StatusNotFound, response) } log.Println("adding elemenet") @@ -115,11 +138,11 @@ func putElement(c echo.Context) error { log.Println("err=", elem.ItemID) response := postElementReturn{elem.ItemID, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { log.Println("res=", elem.ItemID) response := postElementReturn{elem.ItemID, ""} - return c.JSON(http.StatusCreated, response) + return FormattedResponse(c, http.StatusCreated, response) } } @@ -132,15 +155,15 @@ func deleteElement(c echo.Context) error { if err != nil { response := postElementReturn{elem.ItemID, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { err = operations.DeleteElement(itemid) if err != nil { response := postElementReturn{itemid, err.Error()} - return c.JSON(http.StatusInternalServerError, response) + return FormattedResponse(c, http.StatusInternalServerError, response) } else { response := postElementReturn{itemid, ""} - return c.JSON(http.StatusOK, response) + return FormattedResponse(c, http.StatusOK, response) } } } diff --git a/janeserver/services/restapi/endpointsExpectedValues.go b/janeserver/services/restapi/endpointsExpectedValues.go index 965af60..7da88f2 100644 --- a/janeserver/services/restapi/endpointsExpectedValues.go +++ b/janeserver/services/restapi/endpointsExpectedValues.go @@ -1,7 +1,6 @@ package restapi import ( - "fmt" "log" "net/http" @@ -118,12 +117,9 @@ func getExpectedValuesByPolicy(c echo.Context) error { func getExpectedValueByElementAndPolicy(c echo.Context) error { eid := c.Param("eid") pid := c.Param("pid") + epn := c.Param("epn") - fmt.Println("eid", eid, "pid", pid) - - elem, err := operations.GetExpectedValueByElementAndPolicy(eid, pid) - - fmt.Println("\nreturn ", elem, " error", err) + elem, err := operations.GetExpectedValueByElementAndPolicy(eid, pid, epn) if err != nil { log.Println("err=", err) diff --git a/janeserver/services/restapi/endpointsHealth.go b/janeserver/services/restapi/endpointsHealth.go index f527653..0a727c7 100644 --- a/janeserver/services/restapi/endpointsHealth.go +++ b/janeserver/services/restapi/endpointsHealth.go @@ -89,5 +89,5 @@ func health(c echo.Context) error { hstr := healthStructure{objectCount()} - return c.JSON(http.StatusOK, hstr) + return FormattedResponse(c, http.StatusOK, hstr) } diff --git a/janeserver/services/restapi/endpointsLog.go b/janeserver/services/restapi/endpointsLog.go index 19f47b1..181b1ee 100644 --- a/janeserver/services/restapi/endpointsLog.go +++ b/janeserver/services/restapi/endpointsLog.go @@ -32,10 +32,10 @@ func getLogEntries(c echo.Context) error { logentries, err := operations.GetLogEntries(max) if err != nil { - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { rtn := returnLogEntries{logentries, len(logentries), max} - return c.JSON(http.StatusOK, rtn) + return FormattedResponse(c, http.StatusOK, rtn) } } @@ -51,9 +51,9 @@ func getLogEntriesSince(c echo.Context) error { logentries, err := operations.GetLogEntriesSince(duration_query) if err != nil { - return c.JSON(http.StatusInternalServerError, MakeRESTErrorMessage(err)) + return FormattedResponse(c, http.StatusInternalServerError, MakeRESTErrorMessage(err)) } else { rtn := returnLogEntriesSince{logentries, len(logentries), duration_query} - return c.JSON(http.StatusOK, rtn) + return FormattedResponse(c, http.StatusOK, rtn) } } diff --git a/janeserver/services/restapi/endpointsProtocols.go b/janeserver/services/restapi/endpointsProtocols.go index 5887025..e483c73 100644 --- a/janeserver/services/restapi/endpointsProtocols.go +++ b/janeserver/services/restapi/endpointsProtocols.go @@ -9,9 +9,9 @@ import ( ) type protocolExternal struct { - Name string `json:"name",bson:"name"` - Description string `json:"description",bson:"description"` - Intents []string `json:"intents",bson:"intents"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` + Intents []string `json:"intents" bson:"intents"` } type returnProtocols struct { diff --git a/janeserver/services/restapi/endpointsRules.go b/janeserver/services/restapi/endpointsRules.go index f37f9e5..25173fb 100644 --- a/janeserver/services/restapi/endpointsRules.go +++ b/janeserver/services/restapi/endpointsRules.go @@ -10,9 +10,9 @@ import ( ) type ruleExternal struct { - Name string `json:"name",bson:"name"` - Description string `json:"description",bson:"description"` - NeedsEV bool `json:"needsev",bson:"needsev"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` + NeedsEV bool `json:"needsev" bson:"needsev"` } type returnRules struct { diff --git a/janeserver/services/restapi/endpointsSession.go b/janeserver/services/restapi/endpointsSession.go index 44c0def..6ceb0f9 100644 --- a/janeserver/services/restapi/endpointsSession.go +++ b/janeserver/services/restapi/endpointsSession.go @@ -31,7 +31,7 @@ func getSessions(c echo.Context) error { //Marshall into JSON elems_struct := returnSessions{elems_str, len(elems_str)} - return c.JSON(http.StatusOK, elems_struct) + return FormattedResponse(c, http.StatusOK, elems_struct) } } diff --git a/janeserver/services/restapi/initrestapi.go b/janeserver/services/restapi/initrestapi.go index 511f86c..ce9802a 100644 --- a/janeserver/services/restapi/initrestapi.go +++ b/janeserver/services/restapi/initrestapi.go @@ -1,20 +1,24 @@ package restapi import ( + "fmt" "net/http" + "time" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "a10/configuration" "a10/logging" + + "context" ) const PREFIX = "" //const PREFIX="/v3" -func StartRESTInterface() { +func StartRESTInterface(ctx context.Context) { router := echo.New() router.HideBanner = true @@ -22,6 +26,11 @@ func StartRESTInterface() { //not necessary, but I will keep this here because this is now my example of how to use middlewares //in echo, plus the import declaration above router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5})) + router.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + Skipper: middleware.DefaultSkipper, + AllowOrigins: []string{"*"}, + AllowMethods: []string{http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete}, + })) //router.Use(middleware.Logger()) //setup endpoints @@ -36,23 +45,45 @@ func StartRESTInterface() { crt := configuration.ConfigData.Rest.Crt key := configuration.ConfigData.Rest.Key usehttp := configuration.ConfigData.Rest.UseHTTP + listenon := configuration.ConfigData.Web.ListenOn //start the server if usehttp == true { - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "RESTAPI", "REST API HTTP mode starting.") - router.Logger.Fatal(router.Start(port)) - + msg := fmt.Sprintf("REST HTTP mode starting, listening on %v at %v.", listenon, port) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "RESTAPI", msg) + go func() { + if err := router.Start(port); err != nil && err != http.ErrServerClosed { + router.Logger.Fatal("shutting down the server") + } + }() } else { - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "RESTAPI", "REST API HTTPS mode starting.") - router.Logger.Fatal(router.StartTLS(port, crt, key)) + msg := fmt.Sprintf("REST HTTP mode starting, listening on %v at %v.", listenon, port) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "RESTAPI", msg) + go func() { + if err := router.StartTLS(port, crt, key); err != nil && err != http.ErrServerClosed { + router.Logger.Fatal("shutting down the server") + } + }() + } + // Wait for interrupt signal to gracefully shut down the server with a timeout of 10 seconds. + <-ctx.Done() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := router.Shutdown(ctx); err != nil { + router.Logger.Fatal(err) } + msg := fmt.Sprintf("RESI API graceful shutdown") + logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "RESTAPI", msg) + } func setUpOperationEndpoints(router *echo.Echo) { router.GET(PREFIX+"/elements", getElements) router.GET(PREFIX+"/element/:itemid", getElement) router.GET(PREFIX+"/elements/name/:name", getElementsByName) + router.GET(PREFIX+"/elements/tag/:tag", getElementsByTag) router.POST(PREFIX+"/element", postElement) router.PUT(PREFIX+"/element", putElement) router.DELETE(PREFIX+"/element/:itemid", deleteElement) @@ -69,7 +100,7 @@ func setUpOperationEndpoints(router *echo.Echo) { router.GET(PREFIX+"/expectedValues/name/:name", getExpectedValuesByName) router.GET(PREFIX+"/expectedValues/element/:itemid", getExpectedValuesByElement) router.GET(PREFIX+"/expectedValues/intent/:itemid", getExpectedValuesByPolicy) - router.GET(PREFIX+"/expectedValue/:eid/:pid", getExpectedValueByElementAndPolicy) + router.GET(PREFIX+"/expectedValue/:eid/:pid/:epn", getExpectedValueByElementAndPolicy) router.POST(PREFIX+"/expectedValue", postExpectedValue) router.PUT(PREFIX+"/expectedValue", putExpectedValue) @@ -128,16 +159,17 @@ func setUpLoggingEndpoints(router *echo.Echo) { } type homepageData struct { - Name string `json:"name"` - WelcomeMessage string `json:"welcomeMessage"` - Prefix string `json:"prefix"` + Name string `json:"name" xml:"name"` + WelcomeMessage string `json:"welcomeMessage" xml:"welcomeMessage"` + Prefix string `json:"prefix" xml:"prefix"` } func homepage(c echo.Context) error { h := homepageData{"Jane", "Croeso, Tervetuola, Welcome", PREFIX} - return c.JSON(http.StatusOK, h) + + return FormattedResponse(c, http.StatusOK, h) } func config(c echo.Context) error { - return c.JSON(http.StatusOK, configuration.ConfigData) + return FormattedResponse(c, http.StatusOK, configuration.ConfigData) } diff --git a/janeserver/services/restapi/responseformatting.go b/janeserver/services/restapi/responseformatting.go new file mode 100644 index 0000000..239fc52 --- /dev/null +++ b/janeserver/services/restapi/responseformatting.go @@ -0,0 +1,24 @@ +package restapi + +import ( + "github.com/labstack/echo/v4" +) + +// Context, int = http.Status and whatever data +func FormattedResponse(c echo.Context, s int, v interface{}) error { + asform := c.QueryParam("form") + + switch asform { + case "xml": + return c.XML(s, v) + case "json": + return c.JSON(s, v) + case "prettyxml": + return c.XMLPretty(s, v, " ") + case "prettyjson": + return c.JSONPretty(s, v, " ") + default: + return c.JSON(s, v) + } + +} diff --git a/janeserver/services/restapi/resterrors.go b/janeserver/services/restapi/resterrors.go index afe19e7..afe4cab 100644 --- a/janeserver/services/restapi/resterrors.go +++ b/janeserver/services/restapi/resterrors.go @@ -5,7 +5,7 @@ import ( ) type restErrorMessage struct { - ErrorMessage string `json:"error",bson:"error"` + ErrorMessage string `json:"error" bson:"error"` } func MakeRESTErrorMessage(e error) restErrorMessage { diff --git a/janeserver/services/webui/attest.go b/janeserver/services/webui/attest.go index 7d61d01..46eb9c5 100644 --- a/janeserver/services/webui/attest.go +++ b/janeserver/services/webui/attest.go @@ -3,6 +3,7 @@ package webui import ( "fmt" "net/http" + "strings" "github.com/labstack/echo/v4" @@ -27,13 +28,13 @@ func showAttest(c echo.Context) error { } type attestrequest struct { - Eid string `form:"eid"` - Pid string `form:"pid"` - Rn []string `form:"rn"` - Av string `form:"av"` - Pps string `form:"pps"` - Rps string `form:"rps"` - Msg string `form:"msg"` + EidEpn string `form:"eid"` // NOTE this actually contains the eid *AND* the name of the endpoint - comma delimited + Pid string `form:"pid"` + Rn []string `form:"rn"` + Av string `form:"av"` + Pps string `form:"pps"` + Rps string `form:"rps"` + Msg string `form:"msg"` } type multipleresultsummary struct { @@ -47,14 +48,22 @@ type multipleresultsummary struct { func processAttest(c echo.Context) error { var attreq attestrequest + //fmt.Printf("\n processAttest\n") + err := c.Bind(&attreq) if err != nil { fmt.Printf("Error in binding %v", err.Error()) } - fmt.Printf("ATTREQ %v\n", attreq) + // split the EidEpn into its constituent parts + + eid := strings.Split(attreq.EidEpn, ",")[0] + epn := strings.Split(attreq.EidEpn, ",")[1] + + //fmt.Printf(" eid, epn: %v %v \n ", eid, epn) + // Get the objects - e, _ := operations.GetElementByItemID(attreq.Eid) + e, _ := operations.GetElementByItemID(eid) p, _ := operations.GetIntentByItemID(attreq.Pid) // Open a session @@ -67,9 +76,18 @@ func processAttest(c echo.Context) error { empty := make(map[string]interface{}) // Call attest - cid, err := operations.Attest(e, p, s, empty) + cid, err := operations.Attest(e, epn, p, s, empty) + + // need to handle errors here - there will be no claim ID so we can't redirect there + // for the moment, let's go back to the attest page + + if err != nil { + return c.Redirect(http.StatusSeeOther, "/attest") + } + + // - fmt.Printf("return after attests %v %v\n", err, cid) + //fmt.Printf("return after attests %v %v\n", err, cid) //Check if we are attesting only // if so, close the session and redirect to the claim page @@ -86,14 +104,15 @@ func processAttest(c echo.Context) error { cl, _ := operations.GetClaimByItemID(cid) // And perform the verifications <--- note the plural - // This bit needs to be parallelised + // This bit could be parallelised for _, rn := range attreq.Rn { r, _ := operations.GetRule(rn) - fmt.Printf("** verify %v\n", r) + //fmt.Printf("** verify %v\n", r) - rid, rv, err := operations.Verify(cl, r, s, empty) // rps conversion goes here - fmt.Printf("results of verify %v - %v - %v\n", err, rv, rid) + //rid, rv, err := operations.Verify(cl, r, s, empty) // rps conversion goes here + operations.Verify(cl, r, s, empty) // rps conversion goes here + //fmt.Printf("results of verify %v - %v - %v\n", err, rv, rid) } // end of parallelism diff --git a/janeserver/services/webui/claims.go b/janeserver/services/webui/claims.go index 84ea937..dd35963 100644 --- a/janeserver/services/webui/claims.go +++ b/janeserver/services/webui/claims.go @@ -1,7 +1,7 @@ package webui import ( - "fmt" + //"fmt" "net/http" "github.com/labstack/echo/v4" @@ -11,7 +11,6 @@ import ( func showClaims(c echo.Context) error { es, _ := operations.GetClaimsAll() - fmt.Printf("remdering element %v\n", len(es)) return c.Render(http.StatusOK, "claims.html", es) } diff --git a/janeserver/services/webui/elements.go b/janeserver/services/webui/elements.go index 7ecadbf..d004faf 100644 --- a/janeserver/services/webui/elements.go +++ b/janeserver/services/webui/elements.go @@ -40,11 +40,15 @@ func showElement(c echo.Context) error { } func newElement(c echo.Context) error { - return c.Render(http.StatusOK, "editelement.html", nil) + fmt.Println("ELEMTEMPLATE is ", elementtemplate()) + + return c.Render(http.StatusOK, "editelement.html", elementtemplate()) } func processNewElement(c echo.Context) error { + fmt.Println("\nProcessing New Element") elemdata := c.FormValue("elementdata") + fmt.Println("ELEMDATA is ", elemdata) var newelem structures.Element @@ -61,3 +65,65 @@ func processNewElement(c echo.Context) error { return c.Redirect(http.StatusSeeOther, "/elements") } + +// This is the template for an element +func elementtemplate() string { + raw := `{ + "name": "****", + "description": "****", + "endpoints": + { + "tarzan": + { + "endpoint": "http://127.0.0.1:8530", + "protocol": "A10HTTPRESTv2" + }, + "ratsd": + { + "endpoint": "http://127.0.0.1:8853", + "protocol": "RATSD" + } + }, + "tags": + [ + "****1", + "****2" + ], + "host": + { + "os": "****", + "arch": "****", + "hostname": "****", + "machineid": "****" + }, + "tpm2": + { + "device": "/dev/tpmrm0", + "ekcerthandle": "0x01c00002", + "ek": + { + "handle": "0x810100EE", + "public": "****" + }, + "ak": + { + "handle": "0x810100AA", + "public": "****" + } + }, + "uefi": + { + "eventlog": "/sys/kernel/security/tpm0/binary_bios_measurements" + }, + "ima": + { + "asciilog": "/sys/kernel/security/ima/ascii_runtime_measurements" + }, + "txt": + { + "log": "" + } +} + ` + return raw +} diff --git a/janeserver/services/webui/expectedvalues.go b/janeserver/services/webui/expectedvalues.go index ee30eea..705a81e 100644 --- a/janeserver/services/webui/expectedvalues.go +++ b/janeserver/services/webui/expectedvalues.go @@ -1,8 +1,10 @@ package webui import ( + "encoding/json" "fmt" "net/http" + "strings" "github.com/labstack/echo/v4" @@ -41,6 +43,46 @@ func showExpectedValue(c echo.Context) error { return c.Render(http.StatusOK, "ev.html", evstr) } +type editevestruct struct { + Elements []structures.ElementSummary + Intents []structures.Intent +} + func newExpectedValue(c echo.Context) error { - return c.Render(http.StatusOK, "editexpectedvalue.html", nil) + + e, _ := operations.GetElementsSummary() + i, _ := operations.GetIntentsAll() + + evstr := editevestruct{e, i} + + return c.Render(http.StatusOK, "editexpectedvalue.html", evstr) +} + +func processNewExpectedValue(c echo.Context) error { + fmt.Println("\nProcessing New Element") + itemid := c.FormValue("itemid") + name := c.FormValue("name") + description := c.FormValue("description") + elementselect := c.FormValue("elementselect") + intentselect := c.FormValue("intentselect") + evsparameters := c.FormValue("evsparameters") + + // elementSelect is a CSV of itemid COMMA name of endpoint + theelement := strings.Split(elementselect, ",")[0] + endpointname := strings.Split(elementselect, ",")[1] + + var evsparams map[string]interface{} + err := json.Unmarshal([]byte(evsparameters), &evsparams) + if err != nil { + fmt.Printf("error is %v\n", err.Error()) + return c.Redirect(http.StatusSeeOther, "/new/expectedvalue") + } + + var newev = structures.ExpectedValue{itemid, name, description, theelement, endpointname, intentselect, evsparams, structures.RecordHistory{}} + + fmt.Printf(" fv%v\n", newev) + eid, err := operations.AddExpectedValue(newev) + fmt.Printf(" eid=%v,err=%v\n", eid, err) + + return c.Redirect(http.StatusSeeOther, "/expectedvalues") } diff --git a/janeserver/services/webui/homepages.go b/janeserver/services/webui/homepages.go index ecc48c7..1ad7793 100644 --- a/janeserver/services/webui/homepages.go +++ b/janeserver/services/webui/homepages.go @@ -12,18 +12,20 @@ import ( ) type homepagestructure struct { - Nes int - Nps int - Nevs int - Ncs int - Nrs int - Nprs int - Nhs int - Nses int64 - Nrus int - Nlog int64 - Szlog int64 - Cfg *configuration.ConfigurationStruct + Nes int + Nps int + Nevs int + Ncs int + Nrs int + Nprs int + Nhs int + Nses int64 + Nrus int + Nlog int64 + Szlog int64 + Cfg *configuration.ConfigurationStruct + CmdLineLength int + CmdLine []string } func homepage(c echo.Context) error { @@ -60,6 +62,9 @@ func homepage(c echo.Context) error { hps.Cfg = configuration.ConfigData + hps.CmdLineLength = len(os.Args) + hps.CmdLine = os.Args + fmt.Printf("hps is %v\n", hps) return c.Render(http.StatusOK, "home.html", hps) diff --git a/janeserver/services/webui/initwebapi.go b/janeserver/services/webui/initwebapi.go index ae15873..564f9e6 100644 --- a/janeserver/services/webui/initwebapi.go +++ b/janeserver/services/webui/initwebapi.go @@ -5,12 +5,16 @@ import ( "fmt" "html/template" "io" + "net/http" + "time" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "a10/configuration" "a10/logging" + + "context" ) // file embedding @@ -34,23 +38,30 @@ func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c return tmpl.ExecuteTemplate(w, "base.html", data) } -func StartWebUI() { - +func StartWebUI(ctx context.Context) { // Parse the templates templates := make(map[string]*template.Template) // It is done this way so we can have different templates for each operation...a bit ugly, but html/template is not jinja //dev.to/ykyuen/setup-nested-html-template-in-go-echo-web-framework-d9b - functions := template.FuncMap{"defaultMessage": DefaultMessage, "epochToUTC": EpochToUTC, "base64decode": Base64decode, "encodeAsHexString": EncodeAsHexString, "tcgAlg": TCGAlg} + functions := template.FuncMap{ + "defaultMessage": DefaultMessage, "epochToUTCdetailed": EpochToUTCdetailed, "epochToUTC": EpochToUTCsimple, "base64decode": Base64decode, + "encodeAsHexString": EncodeAsHexString, "tcgAlg": TCGAlg, "opaqueObjectInt64": GetOpaqueObjectByValueInt64, + "opaqueObject": GetOpaqueObjectByValue, + } - templates["home.html"] = template.Must(template.ParseFS(WPFS, T+"home.html", T+"base.html")) - templates["help.html"] = template.Must(template.ParseFS(WPFS, T+"help.html", T+"base.html")) - templates["about.html"] = template.Must(template.ParseFS(WPFS, T+"about.html", T+"base.html")) + //templates["home.html"] = template.Must(template.ParseFS(WPFS, T+"home.html", T+"base.html")) + templates["home.html"] = template.Must(template.New("home.html").Funcs(functions).ParseFS(WPFS, T+"home.html", T+"base.html")) + templates["help.html"] = template.Must(template.New("help.html").Funcs(functions).ParseFS(WPFS, T+"help.html", T+"base.html")) + templates["about.html"] = template.Must(template.New("about.html").Funcs(functions).ParseFS(WPFS, T+"about.html", T+"base.html")) - templates["elements.html"] = template.Must(template.ParseFS(WPFS, T+"elements.html", T+"elementsummarylist.html", T+"base.html")) - templates["intents.html"] = template.Must(template.ParseFS(WPFS, T+"intents.html", T+"intentsummarylist.html", T+"base.html")) - templates["evs.html"] = template.Must(template.ParseFS(WPFS, T+"evs.html", T+"evsummarylist.html", T+"base.html")) + templates["elements.html"] = template.Must(template.New("elements.html").Funcs(functions).ParseFS(WPFS, T+"elements.html", T+"elementsummarylist.html", T+"base.html")) + templates["intents.html"] = template.Must(template.New("intents.html").Funcs(functions).ParseFS(WPFS, T+"intents.html", T+"intentsummarylist.html", T+"base.html")) + templates["evs.html"] = template.Must(template.New("evs.html").Funcs(functions).ParseFS(WPFS, T+"evs.html", + T+"evsummarylist.html", + T+"recordhistory.html", + T+"base.html")) templates["element.html"] = template.Must(template.New("element.html").Funcs(functions).ParseFS(WPFS, T+"element.html", T+"base.html", T+"uefi.html", @@ -59,11 +70,14 @@ func StartWebUI() { T+"tpm2.html", T+"tpm2key.html", T+"hostinformation.html", + T+"recordhistory.html", T+"resultvalue.html")) - templates["intent.html"] = template.Must(template.ParseFS(WPFS, T+"intent.html", T+"base.html", + templates["intent.html"] = template.Must(template.New("intent.html").Funcs(functions).ParseFS(WPFS, T+"intent.html", T+"base.html", T+"genericList.html")) - templates["ev.html"] = template.Must(template.ParseFS(WPFS, T+"ev.html", T+"base.html", + templates["ev.html"] = template.Must(template.New("ev.html").Funcs(functions).ParseFS(WPFS, T+"ev.html", + T+"base.html", + T+"recordhistory.html", T+"genericList.html")) templates["claims.html"] = template.Must(template.New("claims.html").Funcs(functions).ParseFS(WPFS, T+"claims.html", T+"base.html")) @@ -73,6 +87,7 @@ func StartWebUI() { T+"claim_ima.html", T+"claim_quote.html", T+"claim_tpm2pcrs.html", + T+"claim_efivars.html", T+"genericList.html")) templates["results.html"] = template.Must(template.New("results.html").Funcs(functions).ParseFS(WPFS, T+"results.html", T+"resultvalue.html", T+"base.html")) @@ -83,18 +98,18 @@ func StartWebUI() { templates["attest.html"] = template.Must(template.New("attest.html").Funcs(functions).ParseFS(WPFS, T+"attest.html", T+"base.html")) - templates["protocols.html"] = template.Must(template.ParseFS(WPFS, T+"protocols.html", T+"base.html")) - templates["rules.html"] = template.Must(template.ParseFS(WPFS, T+"rules.html", T+"base.html")) + templates["protocols.html"] = template.Must(template.New("protocols.html").Funcs(functions).ParseFS(WPFS, T+"protocols.html", T+"base.html")) + templates["rules.html"] = template.Must(template.New("rules.html").Funcs(functions).ParseFS(WPFS, T+"rules.html", T+"base.html")) - templates["log.html"] = template.Must(template.New("log.html").Funcs(functions).ParseFS(WPFS, T+"log.html", - T+"base.html")) + templates["log.html"] = template.Must(template.New("log.html").Funcs(functions).ParseFS(WPFS, T+"log.html", T+"base.html")) - templates["opaqueobjects.html"] = template.Must(template.ParseFS(WPFS, T+"opaqueobjects.html", T+"base.html")) - templates["opaqueobject.html"] = template.Must(template.ParseFS(WPFS, T+"opaqueobject.html", T+"base.html")) + templates["opaqueobjects.html"] = template.Must(template.New("opaqueobjects.html").Funcs(functions).ParseFS(WPFS, T+"opaqueobjects.html", T+"base.html")) + templates["opaqueobject.html"] = template.Must(template.New("opaqueobject.html").Funcs(functions).ParseFS(WPFS, T+"opaqueobject.html", T+"base.html")) templates["editelement.html"] = template.Must(template.New("editelement.html").Funcs(functions).ParseFS(WPFS, T+"editelement.html", T+"base.html")) templates["editintent.html"] = template.Must(template.New("editintent.html").Funcs(functions).ParseFS(WPFS, T+"editintent.html", T+"base.html")) - templates["editexpectedvalue.html"] = template.Must(template.ParseFS(WPFS, T+"editexpectedvalue.html", T+"base.html")) + templates["editexpectedvalue.html"] = template.Must(template.New("editexpectedvalue.html").Funcs(functions).ParseFS(WPFS, T+"editexpectedvalue.html", T+"base.html")) + templates["editopaqueobject.html"] = template.Must(template.New("editopaqueobject.html").Funcs(functions).ParseFS(WPFS, T+"editopaqueobject.html", T+"base.html")) // Create the router router := echo.New() @@ -104,10 +119,13 @@ func StartWebUI() { templates: templates, } - //not necessary, but I will keep this here because this is now my example of how to use middlewares - //in echo, plus the import declaration above + // Middlewares router.Use(middleware.Logger()) - router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5})) + router.Use(middleware.Secure()) + + //Ignore this as it causes issues with nginx and rewriting of URLs + //Easier to let nginx deal with this anyway + //router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5})) //setup endpoints setupHomeEndpoints(router) @@ -120,15 +138,37 @@ func StartWebUI() { crt := configuration.ConfigData.Web.Crt key := configuration.ConfigData.Web.Key usehttp := configuration.ConfigData.Web.UseHTTP + listenon := configuration.ConfigData.Web.ListenOn //start the server if usehttp == true { - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "WEBUI", "WEB UI HTTP mode starting.") - router.Logger.Fatal(router.Start(port)) + msg := fmt.Sprintf("WEB UI HTTP mode starting, listening on %v at %v.", listenon, port) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "WEBUI", msg) + go func() { + if err := router.Start(port); err != nil && err != http.ErrServerClosed { + router.Logger.Fatal("shutting down the server") + } + }() } else { - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "WEBUI", "WEB UI HTTPS mode starting.") - router.Logger.Fatal(router.StartTLS(port, crt, key)) + msg := fmt.Sprintf("WEB UI HTTPS mode starting, listening on %v at %v.", listenon, port) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "WEBUI", msg) + go func() { + if err := router.StartTLS(port, crt, key); err != nil && err != http.ErrServerClosed { + router.Logger.Fatal("shutting down the server") + } + }() + } + + // Wait for interrupt signal to gracefully shut down the server with a timeout of 10 seconds. + <-ctx.Done() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := router.Shutdown(ctx); err != nil { + router.Logger.Fatal(err) } + + msg := fmt.Sprintf("WEB UI graceful shutdown") + logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "WEBUI", msg) } func setupEditEndpoints(router *echo.Echo) { @@ -139,7 +179,12 @@ func setupEditEndpoints(router *echo.Echo) { router.POST(PREFIX+"/new/intent", processNewIntent) router.GET(PREFIX+"/new/expectedvalue", newExpectedValue) + router.POST(PREFIX+"/new/expectedvalue", processNewExpectedValue) + + router.GET(PREFIX+"/loadstandardintents", loadstandardintents) + router.GET(PREFIX+"/new/opaqueobject", newOpaqueObject) + router.POST(PREFIX+"/new/opaqueobject", processOpaqueObject) } func setupHomeEndpoints(router *echo.Echo) { diff --git a/janeserver/services/webui/intents.go b/janeserver/services/webui/intents.go index c3f3c0b..a9f61c7 100644 --- a/janeserver/services/webui/intents.go +++ b/janeserver/services/webui/intents.go @@ -22,7 +22,7 @@ func showIntent(c echo.Context) error { } func newIntent(c echo.Context) error { - return c.Render(http.StatusOK, "editintent.html", nil) + return c.Render(http.StatusOK, "editintent.html", intenttemplate()) } func processNewIntent(c echo.Context) error { @@ -43,3 +43,18 @@ func processNewIntent(c echo.Context) error { return c.Redirect(http.StatusSeeOther, "/intents") } + +// This is the template for an element +func intenttemplate() string { + raw := `{ + "itemid" : "****", + "name" : "****", + "description" : "****", + "function" : "****", + "parameters" : {} + } + ` + return raw +} + +// Standard Intents diff --git a/janeserver/services/webui/opaqueobjects.go b/janeserver/services/webui/opaqueobjects.go index 71adc89..664acfc 100644 --- a/janeserver/services/webui/opaqueobjects.go +++ b/janeserver/services/webui/opaqueobjects.go @@ -1,11 +1,13 @@ package webui import ( + "fmt" "net/http" "github.com/labstack/echo/v4" "a10/operations" + "a10/structures" ) func showOpaqueObjects(c echo.Context) error { @@ -19,3 +21,23 @@ func showOpaqueObject(c echo.Context) error { return c.Render(http.StatusOK, "opaqueobject.html", o) } + +func newOpaqueObject(c echo.Context) error { + + return c.Render(http.StatusOK, "editopaqueobject.html", nil) +} + +func processOpaqueObject(c echo.Context) error { + fmt.Println("\nProcessing New Opaque Object") + value := c.FormValue("value") + otype := c.FormValue("type") + shortdescription := c.FormValue("shortdescription") + longdescription := c.FormValue("longdescription") + + var newoo = structures.OpaqueObject{value, otype, shortdescription, longdescription} + + eid, err := operations.AddOpaqueObject(newoo) + fmt.Printf(" eid=%v,err=%v\n", eid, err) + + return c.Redirect(http.StatusSeeOther, "/opaqueobjects") +} diff --git a/janeserver/services/webui/sessions.go b/janeserver/services/webui/sessions.go index 406a591..b563658 100644 --- a/janeserver/services/webui/sessions.go +++ b/janeserver/services/webui/sessions.go @@ -1,16 +1,20 @@ package webui import ( + "fmt" "github.com/labstack/echo/v4" "net/http" + "time" "a10/operations" "a10/structures" ) type claimsummary struct { - ItemID string - BodyType string + ItemID string + BodyType string + EndpointName string + Timing structures.Timing } type resultsummary struct { @@ -43,11 +47,12 @@ type resultanalytics struct { } type sessionsummary struct { - S structures.Session - CS []claimsummary - RS []resultsummary - CA claimanalytics - RA resultanalytics + S structures.Session + CS []claimsummary + RS []resultsummary + CA claimanalytics + RA resultanalytics + TDIFF string } func showSession(c echo.Context) error { @@ -56,7 +61,7 @@ func showSession(c echo.Context) error { cs := make([]claimsummary, 0) for _, i := range s.ClaimList { cl, _ := operations.GetClaimByItemID(i) - cs = append(cs, claimsummary{cl.ItemID, cl.BodyType}) + cs = append(cs, claimsummary{cl.ItemID, cl.BodyType, cl.Header.EndpointName, cl.Header.Timing}) } rs := make([]resultsummary, 0) @@ -65,10 +70,21 @@ func showSession(c echo.Context) error { rs = append(rs, resultsummary{rl.ItemID, rl.Result, rl.RuleName, rl.VerifiedAt}) } - sstr := sessionsummary{s, cs, rs, genclaimanalytics(cs), genresultanalytics(rs)} + sstr := sessionsummary{s, cs, rs, genclaimanalytics(cs), genresultanalytics(rs), gettimediff(s)} return c.Render(http.StatusOK, "session.html", sstr) } +func gettimediff(s structures.Session) string { + t_o := time.Unix(0, int64(s.Timing.Closed)) + t_c := time.Unix(0, int64(s.Timing.Opened)) + t_diff := t_o.Sub(t_c) + fmt.Printf("S.closed is %v\n", t_o) + fmt.Printf("S.opened is %v\n", t_c) + fmt.Printf("S.diff is %v\n", t_diff) + + return fmt.Sprintf("%v", t_diff) +} + func genclaimanalytics(cs []claimsummary) claimanalytics { var valid int = 0 var errs int = 0 diff --git a/janeserver/services/webui/standardintents.go b/janeserver/services/webui/standardintents.go new file mode 100644 index 0000000..54dc23c --- /dev/null +++ b/janeserver/services/webui/standardintents.go @@ -0,0 +1,63 @@ +package webui + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + //"crypto/sha256" + + "github.com/labstack/echo/v4" + + "a10/operations" + "a10/structures" +) + +const STDINTENTSURL = "https://raw.githubusercontent.com/iolivergithub/jane/refs/heads/main/etc/standardintents/standardintents.json" +const STDINTENTSSHA256 = "https://raw.githubusercontent.com/iolivergithub/jane/refs/heads/main/etc/standardintents/standardintents.sha256" + +func loadstandardintents(c echo.Context) error { + var intentfilestruct []structures.Intent + + stdintents, errints := getfile(STDINTENTSURL) + //stdsha256, err256 := getfile( STDINTENTSSHA256 ) + + if errints != nil { + fmt.Printf("Loading error: I=%v \n", errints.Error()) + return c.Redirect(http.StatusSeeOther, "/intents") + } + + // now parse the JSON string of the intents into a struct + + errjson := json.Unmarshal(stdintents, &intentfilestruct) + if errjson != nil { + fmt.Printf("error unmarshalling JSON %v\n", errjson.Error()) + } + + for _, e := range intentfilestruct { + operations.AddStandardIntent(e) + } + + return c.Redirect(http.StatusSeeOther, "/intents") + +} + +func getfile(url string) ([]byte, error) { + + resp, err := http.Get(url) + + if err != nil { + fmt.Println("getting std intents failed ", err.Error()) + return []byte{}, err + } + + respbody, err2 := ioutil.ReadAll(resp.Body) + defer resp.Body.Close() + + if err2 != nil { + return []byte{}, err2 + } else { + return respbody, nil + } +} diff --git a/janeserver/services/webui/templatefunctions.go b/janeserver/services/webui/templatefunctions.go index d4e6a0c..79f431b 100644 --- a/janeserver/services/webui/templatefunctions.go +++ b/janeserver/services/webui/templatefunctions.go @@ -8,25 +8,40 @@ import ( "encoding/base64" "encoding/hex" + "html/template" + + "a10/operations" "a10/structures" "a10/utilities" "github.com/google/go-tpm/legacy/tpm2" ) -// No idea if this works but it is supposed to be in the html files -func EpochToUTC(epoch structures.Timestamp) string { +func EpochToUTCdetailed(epoch structures.Timestamp) string { + return epochToUTCformat(epoch, true) +} + +func EpochToUTCsimple(epoch structures.Timestamp) string { + return epochToUTCformat(epoch, false) +} + +func epochToUTCformat(epoch structures.Timestamp, detailed bool) string { + // if detailed = true then format goes down to microseconds + var tfmt = "2006-01-02 15:04:05" + if detailed == true { + tfmt = "2006-01-02 15:04:05.0000000" + } sec, err := strconv.ParseInt(fmt.Sprintf("%v", epoch), 10, 64) if err != nil { t := time.Unix(0, 0) - return fmt.Sprintf("%v", t.UTC()) + return fmt.Sprintf("%v", t.UTC().Format(tfmt)) } t := time.Unix(0, sec) - return fmt.Sprintf("%v", t.UTC()) + return fmt.Sprintf("%v", t.UTC().Format(tfmt)) } func DefaultMessage() string { - return "Single invocation from WebUI at " + EpochToUTC(utilities.MakeTimestamp()) + return "Invocation from Jane WebUI initiated " + EpochToUTCdetailed(utilities.MakeTimestamp()) } func Base64decode(u string) string { @@ -41,3 +56,19 @@ func EncodeAsHexString(b []byte) string { func TCGAlg(h int32) string { return tpm2.Algorithm(h).String() } + +func GetOpaqueObjectByValue(v string) template.HTML { + o, err := operations.GetOpaqueObjectByValue(v) + if err != nil { + return template.HTML(v) + } else { + sd := o.Type + " : " + o.ShortDescription + s := `` + v + `` + return template.HTML(s) + } +} + +func GetOpaqueObjectByValueInt64(v int64) template.HTML { + s := strconv.FormatInt(v, 10) + return GetOpaqueObjectByValue(s) +} diff --git a/janeserver/services/webui/templates/about.html b/janeserver/services/webui/templates/about.html index ca48c7e..3610b45 100644 --- a/janeserver/services/webui/templates/about.html +++ b/janeserver/services/webui/templates/about.html @@ -16,7 +16,7 @@
Disclaimer


A Bit of History
-Or, why GA10? There have been various iterations, these are listed below: +Or, why Jane? There have been various iterations, these are listed below:

@@ -40,7 +40,7 @@
A Bit of History
- +
GA102023-2024 Even more compliant with IEFT RATS in its data structures and an improved protocol backend which takes care of layer 7 and layer 6 of the attestation protocols. All the cool stuff of A10 but now written in GO. Seriously strong typing is so important....Reworked UI, reworked REST API and reworked data structures. Oh so much better. AND, Go has a really nice cross compiler: arm, arm64, i386, amd64, ppc, and then Linux, Windows, Solaris, AIX and Plan 9 from Bell Labs. Also Go makes self-contained binaries so the trust agent is a single binary which makes distribution trivial and the whole server engine itself just needs the binary and the config file :-)
Jane2024-! Forked from the original Nokia version and rewritten significantly
Jane2024-!Forked from the original Nokia version and rewritten significantly. But, I hear you ask, why Jane? Well...there were reasons but in the end we chose a name - it was supposed to be allied with an institution that would have made sense with the name, but they were not interested in series cybersecurity research - but the name stuck, and it gave us a chance to properly rename the trust agent....Tarzan...who says us cybersecurity beings don't have a sense of humour?

diff --git a/janeserver/services/webui/templates/attest.html b/janeserver/services/webui/templates/attest.html index 202af0b..bbddea1 100644 --- a/janeserver/services/webui/templates/attest.html +++ b/janeserver/services/webui/templates/attest.html @@ -18,9 +18,11 @@

Attest

- + {{ range $i,$e := .ES }} + {{ range $j,$ep := $e.Endpoints }} + + {{ end }} {{ end }}
@@ -28,9 +30,9 @@

Attest

- {{ range .IS }} - + {{ end }}
@@ -38,7 +40,7 @@

Attest

- {{ range .RS }} {{ end }} @@ -70,12 +72,12 @@

Attest

- +
- +
diff --git a/janeserver/services/webui/templates/attestsummary.html b/janeserver/services/webui/templates/attestsummary.html index 324be8e..7f33b44 100644 --- a/janeserver/services/webui/templates/attestsummary.html +++ b/janeserver/services/webui/templates/attestsummary.html @@ -10,12 +10,12 @@

Session

ItemID {{ .ItemID }} - Opened {{ epochToUTC .Timing.Opened }} + Opened {{ epochToUTCdetailed .Timing.Opened }} Closed {{ if eq .Timing.Closed "0" }} Session still open {{ else }} - {{ epochToUTC .Timing.Closed }} + {{ epochToUTCdetailed .Timing.Closed }} {{ end }} #Claims {{ len .ClaimList }} diff --git a/janeserver/services/webui/templates/base.html b/janeserver/services/webui/templates/base.html index f823792..58cc53c 100644 --- a/janeserver/services/webui/templates/base.html +++ b/janeserver/services/webui/templates/base.html @@ -1,88 +1,95 @@ - - - JANE Web User Interface - - + + + JANE User Interface + + + + - - + - - - + + + + - + + + + + - - +
+
+ {{block "content" .}}{{end}} +
+ + \ No newline at end of file diff --git a/janeserver/services/webui/templates/claim.html b/janeserver/services/webui/templates/claim.html index 31c0b74..01c0fe8 100644 --- a/janeserver/services/webui/templates/claim.html +++ b/janeserver/services/webui/templates/claim.html @@ -1,85 +1,81 @@ {{define "content"}} - -

Claim

-
-
-
- -
Header
- - - - - - - - - - - - - - - - - - - - - -
FieldValue
ItemID {{ .ItemID }}
BodyType {{ .BodyType }}
Element {{ .Header.Element.Name }}
-- Protocol {{ .Header.Element.Protocol }}
-- Endpoint {{ .Header.Element.Endpoint }}
Intent {{ .Header.Intent.Name }}
-- Intent {{ .Header.Intent.Function }}
Session {{ .Header.Session.ItemID }}
Additional Parameters {{ .Header.AdditionalParameters }}
Call Parameters {{ .Header.CallParameters }}
Requested {{ epochToUTC .Header.Timing.Requested }}
Received {{ epochToUTC .Header.Timing.Received }}
- -
-
+
+
+
Header
+ + + + + + + + + + + + + + + + + + +
FieldValue
ItemID, BodyType {{ .ItemID }} {{ .BodyType }}
Element {{ .Header.Element.Name }}   {{ .Header.EndpointName }} {{ .Header.Endpoint.Protocol }}   {{ .Header.Endpoint.Endpoint }}
Intent {{ .Header.Intent.Name }} {{ .Header.Intent.Function }}
Session {{ .Header.Session.ItemID }}
Additional Parameters {{ .Header.AdditionalParameters }}
Call Parameters {{ .Header.CallParameters }}
Requested, Received {{ epochToUTCdetailed .Header.Timing.Requested }}   {{ epochToUTCdetailed .Header.Timing.Received }}
+
+ +
+
Footer
+ + + + + + + + + + + +
FieldValue
Hash {{ encodeAsHexString .Footer.Hash }}
Signature {{ encodeAsHexString .Footer.Signature }}
+
+
-
Footer
- - - - - - - - - - - -
FieldValue
Hash {{ encodeAsHexString .Footer.Hash }}
Signature {{ encodeAsHexString .Footer.Signature }}
- -
-
+
+
+
Body:
+ {{ if eq .BodyType "*ERROR" }} +

{{ .BodyType }}

+ {{ template "claim_ERROR.html" .Body }} + {{ end }} + {{ if eq .BodyType "sys/info" }} +

{{ .BodyType }}

+ {{ template "genericList.html" .Body }} + {{ end }} + {{ if eq .BodyType "ima/asciilog" }} +

{{ .BodyType }}

+ {{ template "claim_ima.html" .Body }} + {{ end }} + {{ if eq .BodyType "tpm2/pcrs" }} +

{{ .BodyType }}

+ {{ template "claim_tpm2pcrs.html" .Body }} + {{ end }} + {{ if eq .BodyType "tpm2/newpcrs" }} +

{{ .BodyType }}

+ {{ template "claim_tpm2pcrs.html" .Body }} + {{ end }} + {{ if eq .BodyType "tpm2/quote" }} +

{{ .BodyType }}

+ {{ template "claim_quote.html" .Body }} + {{ end }} + {{ if eq .BodyType "uefi/efivars" }} +

{{ .BodyType }}

+ {{ template "claim_efivars.html" .Body }} + {{ end }} +
+
- -
Body:
- -{{ if eq .BodyType "*ERROR" }} -

{{ .BodyType }}

- {{ template "claim_ERROR.html" .Body }} -{{ end }} - -{{ if eq .BodyType "sys/info" }} -

{{ .BodyType }}

- {{ template "genericList.html" .Body }} -{{ end }} - -{{ if eq .BodyType "ima/asciilog" }} -

{{ .BodyType }}

- {{ template "claim_ima.html" .Body }} -{{ end }} - -{{ if eq .BodyType "tpm2/pcrs" }} -

{{ .BodyType }}

- {{ template "claim_tpm2pcrs.html" .Body }} -{{ end }} - -{{ if eq .BodyType "tpm2/quote" }} -

{{ .BodyType }}

- {{ template "claim_quote.html" .Body.parsed }} -{{ end }} -
Raw
{{ .Body }} - -{{end}} +{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/claim_efivars.html b/janeserver/services/webui/templates/claim_efivars.html new file mode 100644 index 0000000..2c4f537 --- /dev/null +++ b/janeserver/services/webui/templates/claim_efivars.html @@ -0,0 +1,21 @@ +{{define "claim_efivars.html"}} + +

Count {{ .count }}

+ + + + {{ range .efivars }} + + + + + + + + {{ end }} + +
{{ .name }}{{ .value }}{{ .attributes }}{{ .somevalue }}{{ .errorvalue }}
+ +{{end}} + + \ No newline at end of file diff --git a/janeserver/services/webui/templates/claim_quote.html b/janeserver/services/webui/templates/claim_quote.html index 2aeb332..947b39e 100644 --- a/janeserver/services/webui/templates/claim_quote.html +++ b/janeserver/services/webui/templates/claim_quote.html @@ -1,44 +1,56 @@ {{define "claim_quote.html"}} + + +
Quote
- - - - - - - - - - - + + + + + + + + + + - - {{ if eq .signature.Alg 20 }} - - {{ else }} - - {{ end }} - +
PCR Digest{{ .quote.AttestedQuoteInfo.PCRDigest }}
PCR Selection{{ tcgAlg .quote.AttestedQuoteInfo.PCRSelection.Hash }} : - {{ range .quote.AttestedQuoteInfo.PCRSelection.PCRs }} - {{ . }} - {{ end }} -
Firmware{{ .quote.FirmwareVersion }}
Magic & Type{{ .quote.Magic }}, {{ .quote.Type }}
Extra Data{{ .quote.ExtraData }}
Clock{{ .quote.ClockInfo.Clock }}
Reset Count{{ .quote.ClockInfo.ResetCount }}
Restart Count{{ .quote.ClockInfo.RestartCount }}
Safe - {{ if .quote.ClockInfo.Safe}} - Safe ({{ .quote.ClockInfo.Safe }}) +
FieldReported value
PCR Digest{{ .quote.attested.pcrdigest }}
PCR Selection{{ .quote.attested.pcrselect }}
Firmware{{ .quote.firmwareVersion }}
Magic{{ .quote.magic }} (default value is ff544347)
Type{{ .quote.type }} (default value is 8018)
ClockInfo + + + + + + + - - - + + +
Clock{{ .quote.clockinfo.clock }}
Reset{{ .quote.clockinfo.resetcount }}
Restart{{ .quote.clockinfo.restartcount }}
Safe + {{ if .quote.clockinfo.safe }} + Safe ({{ .quote.clockinfo.safe }}) {{ else }} - Unsafe ({{ .quote.ClockInfo.Safe }}) + Unsafe ({{ .quote.clockinfo.safe }}) {{ end }} -
Qualified Signer{{ .quote.QualifiedSigner.Digest.Alg }} {{ .quote.QualifiedSigner.Digest.Value }}
+ +
Signing Algorithm{{ tcgAlg .signature.Alg }}
RSA{{ tcgAlg .signature.RSA.HashAlg }} {{ .signature.RSA.Signature }}
ECC{{ tcgAlg .signature.ECC.HashAlg }} {{ .signature.ECC.Signature }}
Qualified Signer{{ .quote.qualifiedsigner }}
+ +
Signature
+ + + + + + + + +
FieldReported value
Algorithm{{ .signature.SigAlg }} (default value is 20 for RSASSA)
Signature{{ .signature.Signature }}
{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/claim_tpm2pcrs.html b/janeserver/services/webui/templates/claim_tpm2pcrs.html index a973b7b..d5c77b5 100644 --- a/janeserver/services/webui/templates/claim_tpm2pcrs.html +++ b/janeserver/services/webui/templates/claim_tpm2pcrs.html @@ -4,18 +4,17 @@ {{ range $key, $value := . }} {{ $key }} - {{ range $pkey, $pvalue := $value }} - + {{ end }}
{{ $pkey }}{{ $pvalue }}{{ opaqueObject $pvalue }}
- - + + {{ end }} diff --git a/janeserver/services/webui/templates/claims.html b/janeserver/services/webui/templates/claims.html index c023d8a..3fdb200 100644 --- a/janeserver/services/webui/templates/claims.html +++ b/janeserver/services/webui/templates/claims.html @@ -7,7 +7,8 @@

Claims

Requested Received Element - Policy + Endpoint + Intent Session @@ -21,9 +22,10 @@

Claims

{{ .BodyType }} {{ epochToUTC .Header.Timing.Requested }} {{ epochToUTC .Header.Timing.Received }} - {{ .Header.Element.Name }} + {{ .Header.Element.Name }} + {{ .Header.Endpoint.Protocol }}   {{ .Header.Endpoint.Endpoint }} {{ .Header.Intent.Name }} - {{ .Header.Session.ItemID }} + {{ .Header.Session.ItemID }} {{end}} diff --git a/janeserver/services/webui/templates/editelement.html b/janeserver/services/webui/templates/editelement.html index 21b3e3a..693d862 100644 --- a/janeserver/services/webui/templates/editelement.html +++ b/janeserver/services/webui/templates/editelement.html @@ -1,11 +1,13 @@ {{define "content"}}

Element

+ +
- +
@@ -16,14 +18,21 @@

Element

Instructions

The above must be valid JSON

-

The protocol must be of a valid type

-

The UEFI, TPM2, IMA and TXT sections can be removed if these do not apply

-

If a new element is being created, then the itemid field will be overwritten and an identifier automatically generated

+

If a new element is being created, then the itemid field will be overwritten and an identifier automatically generated

-
+ + {{end}} diff --git a/janeserver/services/webui/templates/editexpectedvalue.html b/janeserver/services/webui/templates/editexpectedvalue.html index 6940118..015a60b 100644 --- a/janeserver/services/webui/templates/editexpectedvalue.html +++ b/janeserver/services/webui/templates/editexpectedvalue.html @@ -1,38 +1,90 @@ {{define "content"}}

Expected Value

+ +
+
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
- + + + {{ range $i,$e := .Elements }} + {{ range $j,$ep := $e.Endpoints }} + + {{ end }} + {{ end }} + +
- + {{ range .Intents }} + + {{ end }}
-
+
+
-
+
- + +
+
+
+

Templates:

+

+   + + +

+

+   +
+
+

+ + +
-
-
- +
+ +
+
@@ -46,5 +98,35 @@

Instructions

+ + {{end}} diff --git a/janeserver/services/webui/templates/editintent.html b/janeserver/services/webui/templates/editintent.html index 7fd5185..bbbb774 100644 --- a/janeserver/services/webui/templates/editintent.html +++ b/janeserver/services/webui/templates/editintent.html @@ -1,10 +1,13 @@ {{define "content"}}

Intent

+ + +
- +
@@ -20,6 +23,14 @@

Instructions

- + {{end}} diff --git a/janeserver/services/webui/templates/editopaqueobject.html b/janeserver/services/webui/templates/editopaqueobject.html new file mode 100644 index 0000000..6ea164f --- /dev/null +++ b/janeserver/services/webui/templates/editopaqueobject.html @@ -0,0 +1,51 @@ +{{define "content"}} +

Opaque Object

+ +
+ +
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+ +
+ +
+
+
+

Instructions

+

The above object parameters are freeform. However the value is the key field and will be used for searches etc

+
+
+ +
+ + + +{{end}} diff --git a/janeserver/services/webui/templates/element.html b/janeserver/services/webui/templates/element.html index c7008d4..ec5ec27 100644 --- a/janeserver/services/webui/templates/element.html +++ b/janeserver/services/webui/templates/element.html @@ -1,146 +1,139 @@ {{define "content"}} - - -

Element {{.E.Name}}

- - - - - - - - - - - - - - -
FieldValue
Name, ItemID {{ .E.Name }}   {{ .E.ItemID }}
Description {{ .E.Description }}
Protocol, Endpoint {{ .E.Protocol }}   {{ .E.Endpoint }}
Tags {{ range .E.Tags }} - {{ . }} - {{end}}
- -
- +

{{.E.Name}}

-
- -
Results
- - - - - - - - - - - - {{ range .RS }} - - - - - - - - - {{end}} - -
RuleNameVerifiedAtResult
{{ .RuleName }}{{ epochToUTC .VerifiedAt }} -{{ template "resultvalue.html" .Result }} - -
+
+ + + + + + +
ItemID {{ .E.ItemID }}
Description {{ .E.Description }}
Tags {{ range .E.Tags }} + {{ . }} + {{end}}
+
+ + + {{ range $i, $v := .E.Endpoints }} + + + + {{end}} + +
{{ $i }} {{ $v.Protocol }} {{ $v.Endpoint }}
+ +
+
+ #Sessions + #Resuts + #Claims +
+

-
-
- - -
Claims
- - - - - - - - - - - {{ range .CS }} - {{ if eq .BodyType "*ERROR"}} - - {{else}} - - {{end}} - - - - - {{end}} - - -
BodyTypeRequestedPolicy
{{ .BodyType }}{{ epochToUTC .Header.Timing.Requested }}{{ .Header.Intent.Name }}S
- - -
+
+
+ {{ if not .E.TPM2.Device }} + No TPM device present + {{ else }} + {{ template "tpm2.html" .E.TPM2 }} + {{ end }}
+
+ {{ if not .E.RecordHistory }} + No record history + {{ else }} + {{ template "recordhistory.html" .E.RecordHistory }} + {{ end }} +
- - - - - -
Additional Attributes
- -{{ if not .E.TPM2.Device }} -{{ else }} -
-
Trusted Platform Module 2.0 (TPM)
- {{ template "tpm2.html" .E.TPM2 }} -{{ end }} - - -{{ if not .E.UEFI.Eventlog }} -{{ else }} -
- -
Unified Extensible Firmware Interface (UEFI)
- {{ template "uefi.html" .E.UEFI }} -{{ end }} - - - -{{ if not .E.IMA.ASCIILog }} -{{ else }} -
- -
Integrity Measurement Architecture (IMA)
- {{ template "ima.html" .E.IMA }} -{{ end }} - - -{{ if not .E.TXT.Log }} -{{ else }} -
- -
Intel Trusted Execution Technology (TXT)
- {{ template "txt.html" .E.TXT }} -{{ end }} - -{{ if not .E.Host.Arch }} -{{ else }} +
+ {{ if not .E.Host.Arch }} +
    +
  • No host information specified +
  • +
+ {{ else }} + {{ template "hostinformation.html" .E.Host }} + {{ end }}
- -
Host Information
- {{ template "hostinformation.html" .E.Host }} -{{ end }} - +
    + {{ if not .E.UEFI.Eventlog }} +
  • No UEFI log specified
  • + {{ else }} +
  • UEFI Present
  • + {{ end }} + {{ if not .E.IMA.ASCIILog }} +
  • No IMA log specified
  • + {{ else }} +
  • Linux IMA Present
  • + {{ end }} + {{ if not .E.TXT.Log }} +
  • No TXT log specified
  • + {{ else }} +
  • Intel TXT Present
  • + {{ end }} +
+
+
+
-{{ .E }} - -{{end}} +
+
+
Results
+ + + + + + + + + + + {{ range .RS }} + + + + + + {{end}} + +
RuleNameVerifiedAtResult
{{ .RuleName }}{{ epochToUTC .VerifiedAt }} + {{ template "resultvalue.html" .Result }} +
+
+
+
+
Claims
+ + + + + + + + + + + + {{ range .CS }} + {{ if eq .BodyType "*ERROR"}} + + {{else}} + + {{end}} + + + + + + {{end}} + + +
TypeEndpointRequestedIntent
{{ .BodyType }}{{ .Header.EndpointName }}{{ epochToUTC .Header.Timing.Requested }}{{ .Header.Intent.Name }}
+
+
+{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/elements.html b/janeserver/services/webui/templates/elements.html index ea207db..eb4a03f 100644 --- a/janeserver/services/webui/templates/elements.html +++ b/janeserver/services/webui/templates/elements.html @@ -6,8 +6,7 @@

Elements

Name Description Tags - Protocol - Endpoint + Endpoints diff --git a/janeserver/services/webui/templates/elementsummarylist.html b/janeserver/services/webui/templates/elementsummarylist.html index 6c8cd02..764635e 100644 --- a/janeserver/services/webui/templates/elementsummarylist.html +++ b/janeserver/services/webui/templates/elementsummarylist.html @@ -1,11 +1,16 @@ {{define "elementsummarylist.html"}} {{ .Name }} {{ .Description }} - {{ range .Tags }} + {{ range .Tags }} {{ . }} - {{end}} -{{ .Protocol }} -{{ .Endpoint }} -{{end}} - - +{{end}} + + + {{ range $i, $v := .Endpoints }} + + + + {{end}} +
{{ $i }} {{ $v.Protocol }} {{ $v.Endpoint }}
+ +{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/ev.html b/janeserver/services/webui/templates/ev.html index 3a50c74..c2f4763 100644 --- a/janeserver/services/webui/templates/ev.html +++ b/janeserver/services/webui/templates/ev.html @@ -13,7 +13,9 @@

Expected Value {{ .EV.Name }}

Description {{ .EV.Description }} ItemID {{ .EV.ItemID }} - Element {{ .E.Name }} @ {{ .E.Endpoint }} {{ .E.Protocol }} + Element {{ .E.Name }} + + Endpoint Name {{ .EV.EndpointName }} Intent {{ .I.Name }} {{ .I.Function }} EVS Parameters {{ template "genericList.html" .EV.EVS }} @@ -22,5 +24,12 @@

Expected Value {{ .EV.Name }}

+
+ + {{ if not .EV.RecordHistory }} + No record history + {{ else }} + {{ template "recordhistory.html" .EV.RecordHistory }} + {{ end }} {{end}} diff --git a/janeserver/services/webui/templates/evs.html b/janeserver/services/webui/templates/evs.html index d78c650..3c439b6 100644 --- a/janeserver/services/webui/templates/evs.html +++ b/janeserver/services/webui/templates/evs.html @@ -8,9 +8,9 @@

Expected Values

Name Description Element - Endpoint - Policy - Intent + Endpoint Name + Intent + Function diff --git a/janeserver/services/webui/templates/evsummarylist.html b/janeserver/services/webui/templates/evsummarylist.html index cf0a51e..a530609 100644 --- a/janeserver/services/webui/templates/evsummarylist.html +++ b/janeserver/services/webui/templates/evsummarylist.html @@ -2,7 +2,7 @@ {{ .EV.Name }} {{ .EV.Description }} {{ .E.Name }} -{{ .E.Endpoint }} +{{ .EV.EndpointName }} {{ .I.Name }} {{ .I.Function }} diff --git a/janeserver/services/webui/templates/help.html b/janeserver/services/webui/templates/help.html index 4e55fd6..a534fe3 100644 --- a/janeserver/services/webui/templates/help.html +++ b/janeserver/services/webui/templates/help.html @@ -1,7 +1,15 @@ {{define "content"}}
-

There is not a lot of help in this version either...

-

sorry.

+

Help

+
+Help can be found on the Github pages for this project. Here are the main links + + +also, there's a useful TPMCourse here. +
{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/home.html b/janeserver/services/webui/templates/home.html index b52467c..b5c385c 100644 --- a/janeserver/services/webui/templates/home.html +++ b/janeserver/services/webui/templates/home.html @@ -1,6 +1,4 @@ {{define "content"}} -

{{ .Cfg.System.Name }}


-
@@ -13,156 +11,146 @@

{{ .Nps }}

-
+
+

{{ .Nevs }}

-
+
+

{{ .Nses }}

-
+ + -
+

{{ .Ncs }}

-
-
- -

{{ .Nrs }}

-
-
-
- -

{{ .Nhs }}

-
-
-
- -

{{ .Nprs }} / {{ .Nrus }}

-
-
- - -
- -
-
-
-
-
Database
-
- - - - - - -
Name {{ .Cfg.Database.Name }}
Connection {{ .Cfg.Database.Connection }}
- +
+
+ +

{{ .Nrs }}

+
+
+
+ +

{{ .Nhs }}

+
+
+
+ +

{{ .Nprs }} / {{ .Nrus }}

+
+
-
-
- -
-
-
Messaging
-
- - - - - - - +
+
+ +
+
+
+
Command Line
+
+ Arguments: {{ .CmdLineLength }} : + {{ range .CmdLine }} + {{ . }} + {{end}} +
+
+
+
+
+
+
+
+
Services
+
+
Broker {{ .Cfg.Messaging.Broker }}
Port {{ .Cfg.Messaging.Port }}
Client ID {{ .Cfg.Messaging.ClientID }}
+ + + + + + + +
REST {{ .Cfg.Rest.ListenOn }}:{{ .Cfg.Rest.Port }} + {{ if eq .Cfg.Rest.UseHTTP true }} + http + {{ else }} + https + {{ end }}
Web {{ .Cfg.Web.ListenOn }}:{{ .Cfg.Web.Port }} + {{ if eq .Cfg.Web.UseHTTP true }} + http + {{ else }} + https + {{ end }}
X3270 :{{ .Cfg.X3270.Port }}
Keylime + {{ if eq .Cfg.Keylime.ApiUrl "" }} + Not utilised + {{ else }} + {{ .Cfg.Keylime.ApiUrl }} + {{ end }}
+
+
+
+
+
+ +
+ + + + + + +
Location {{ .Cfg.Logging.LogFileLocation }}
Entries {{ .Nlog }}
Size on disk {{ .Szlog }} bytes
Session update logging {{ if eq .Cfg.Logging.SessionUpdateLogging true }} + enabled + {{ else }} + disabled + {{ end }}
-
-
+
-
- -
- - +
-
Services
+
Database (Mongodb)
- - - - - - - - - - + + +
REST :{{ .Cfg.Rest.Port }} - {{ if eq .Cfg.Rest.UseHTTP true }} - http - {{ else }} - https - {{ end }}
Web :{{ .Cfg.Web.Port }} - {{ if eq .Cfg.Web.UseHTTP true }} - http - {{ else }} - https - {{ end }}
X3270 :{{ .Cfg.X3270.Port }}
Keylime - {{ if eq .Cfg.Keylime.ApiUrl "" }} - Not utilised - {{ else }} - {{ .Cfg.Keylime.ApiUrl }} - {{ end }}
Name {{ .Cfg.Database.Name }}
Connection {{ .Cfg.Database.Connection }}
- - -
-
-
- - - -
+
+
+
- +
Message Bus (MQTT)
- - - - - - + + + +
Location {{ .Cfg.Logging.LogFileLocation }}
Entries {{ .Nlog }}
Size on disk {{ .Szlog }} bytes
Session update logging {{ if eq .Cfg.Logging.SessionUpdateLogging true }} - enabled - {{ else }} - disabled - {{ end }}
Broker {{ .Cfg.Messaging.Broker }}
Port {{ .Cfg.Messaging.Port }}
Client ID {{ .Cfg.Messaging.ClientID }}
-
-
- - -
+ + - - +
- - - + {{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/hostinformation.html b/janeserver/services/webui/templates/hostinformation.html index 1b0d73a..6d232f7 100644 --- a/janeserver/services/webui/templates/hostinformation.html +++ b/janeserver/services/webui/templates/hostinformation.html @@ -3,6 +3,7 @@ Hostname {{ .Hostname }} OS / Arch {{ .OS }} {{ .Arch }} + MachineID {{ .MachineID }} {{end}} diff --git a/janeserver/services/webui/templates/intent.html b/janeserver/services/webui/templates/intent.html index 08bf3fa..842c50e 100644 --- a/janeserver/services/webui/templates/intent.html +++ b/janeserver/services/webui/templates/intent.html @@ -1,5 +1,5 @@ {{define "content"}} -

Policy: {{ .Name }}

+

Intent: {{ .Name }}

diff --git a/janeserver/services/webui/templates/log.html b/janeserver/services/webui/templates/log.html index 6c79da7..e9a645e 100644 --- a/janeserver/services/webui/templates/log.html +++ b/janeserver/services/webui/templates/log.html @@ -1,8 +1,11 @@ {{define "content"}}

Log

Showing {{ .Amount }} entries of {{ .Count }} for duration {{ .Duration }}

+ + +
-
+
@@ -23,7 +26,7 @@

Log

{{else}} {{end}} - +
Timestamp
{{ epochToUTC .Timestamp }}{{ epochToUTCdetailed .Timestamp }} {{ .Channel }} {{ .Operation }} @@ -48,6 +51,30 @@

Log

{{end}}
+ + + {{end}} diff --git a/janeserver/services/webui/templates/opaqueobjects.html b/janeserver/services/webui/templates/opaqueobjects.html index e67880b..2f08874 100644 --- a/janeserver/services/webui/templates/opaqueobjects.html +++ b/janeserver/services/webui/templates/opaqueobjects.html @@ -6,7 +6,6 @@

Opaque Objects

Value Type Short Description - diff --git a/janeserver/services/webui/templates/quotebody.tmp b/janeserver/services/webui/templates/quotebody.tmp new file mode 100644 index 0000000..c91c0b3 --- /dev/null +++ b/janeserver/services/webui/templates/quotebody.tmp @@ -0,0 +1,45 @@ +{{define "claim_quote.html"}} + + + + + + + + + + + + + + + + + + + + + {{ if eq .signature.Alg 20 }} + + {{ else }} + + {{ end }} + + + + +
PCR Digest{{ .quote.AttestedQuoteInfo.PCRDigest }}
PCR Selection{{ tcgAlg .quote.AttestedQuoteInfo.PCRSelection.Hash }} : + {{ range .quote.AttestedQuoteInfo.PCRSelection.PCRs }} + {{ . }} + {{ end }} +
Firmware{{ opaqueObjectInt64 .quote.FirmwareVersion }}
Magic & Type{{ .quote.Magic }}, {{ .quote.Type }}
Extra Data{{ .quote.ExtraData }}
Clock{{ .quote.ClockInfo.Clock }}
Reset Count{{ .quote.ClockInfo.ResetCount }}
Restart Count{{ .quote.ClockInfo.RestartCount }}
Safe + {{ if .quote.ClockInfo.Safe}} + Safe ({{ .quote.ClockInfo.Safe }}) + {{ else }} + Unsafe ({{ .quote.ClockInfo.Safe }}) + {{ end }} +
Qualified Signer{{ .quote.QualifiedSigner.Digest.Alg }} {{ .quote.QualifiedSigner.Digest.Value }}
Signing Algorithm{{ tcgAlg .signature.Alg }}
RSA{{ tcgAlg .signature.RSA.HashAlg }} {{ .signature.RSA.Signature }}
ECC{{ tcgAlg .signature.ECC.HashAlg }} {{ .signature.ECC.Signature }}
+ +{{end}} + + \ No newline at end of file diff --git a/janeserver/services/webui/templates/recordhistory.html b/janeserver/services/webui/templates/recordhistory.html new file mode 100644 index 0000000..1df2d4f --- /dev/null +++ b/janeserver/services/webui/templates/recordhistory.html @@ -0,0 +1,22 @@ +{{define "recordhistory.html"}} + + + + + + {{ if not .LastUpdated }} + + {{ else }} + + {{ end }} + + {{ if not .Archived }} + + {{ else }} + + + {{ end }} + + +
Created {{ epochToUTC .Created }}
Last Updated No updates
Last Updated {{ epochToUTC .LastUpdated }}
Archived Not archived
Archived {{ epochToUTC .Archived }}
Archival Reason {{ .Reason }}
+{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/result.html b/janeserver/services/webui/templates/result.html index f7921b3..24359b6 100644 --- a/janeserver/services/webui/templates/result.html +++ b/janeserver/services/webui/templates/result.html @@ -11,7 +11,7 @@
Element Information
Rule Name {{ .R.RuleName }} - VerifiedAt {{ epochToUTC .R.VerifiedAt }} + VerifiedAt {{ epochToUTCdetailed .R.VerifiedAt }} Result {{ template "resultvalue.html" .R.Result }} Expected Value {{ .R.EV_Name }} Element {{ .R.EVEName }} diff --git a/janeserver/services/webui/templates/scraps b/janeserver/services/webui/templates/scraps deleted file mode 100644 index 139cc46..0000000 --- a/janeserver/services/webui/templates/scraps +++ /dev/null @@ -1,45 +0,0 @@ - - diff --git a/janeserver/services/webui/templates/session.html b/janeserver/services/webui/templates/session.html index e46d1d2..4aedda4 100644 --- a/janeserver/services/webui/templates/session.html +++ b/janeserver/services/webui/templates/session.html @@ -9,14 +9,13 @@

Session

- ItemID {{ .S.ItemID }} - Opened {{ epochToUTC .S.Timing.Opened }} - Closed - {{ if eq .S.Timing.Closed 0 }} - Session still open - {{ else }} - {{ epochToUTC .S.Timing.Closed }} - {{ end }} + ItemID {{ .S.ItemID }} + Timing {{ epochToUTCdetailed .S.Timing.Opened }}  →  + {{ if eq .S.Timing.Closed 0 }} + Session still open + {{ else }} + {{ .TDIFF }}  →  {{ epochToUTCdetailed .S.Timing.Closed }} + {{ end }} #Claims / #Results {{ len .S.ClaimList }} / {{ len .S.ResultList }} Message {{ .S.Message }} @@ -72,7 +71,12 @@

Session

{{ range .CS }} - + + + + + + {{ end }}
{{ .BodyType }}
{{ .BodyType }}{{ .EndpointName }} {{ epochToUTC .Timing.Requested }}{{ epochToUTC .Timing.Received }}
diff --git a/janeserver/services/webui/templates/sessions.html b/janeserver/services/webui/templates/sessions.html index 6066bd8..f501d01 100644 --- a/janeserver/services/webui/templates/sessions.html +++ b/janeserver/services/webui/templates/sessions.html @@ -12,12 +12,12 @@

Sessions

{{ range . }} - {{ epochToUTC .Timing.Opened }} + {{ epochToUTCdetailed .Timing.Opened }} {{ if eq .Timing.Closed 0 }} session open {{ else }} - {{ epochToUTC .Timing.Closed }} + {{ epochToUTCdetailed .Timing.Closed }} {{ end }} {{ .Message }} diff --git a/janeserver/services/webui/templates/tpm2.html b/janeserver/services/webui/templates/tpm2.html index 9572043..b2c37a7 100644 --- a/janeserver/services/webui/templates/tpm2.html +++ b/janeserver/services/webui/templates/tpm2.html @@ -1,15 +1,12 @@ {{define "tpm2.html"}} - - - - - - - + + + +
TPM Device {{ .Device }}
EK Certificate NVRAM Handle {{ .EKCertHandle }}
Endorsement Key {{ template "tpm2key.html" .EK }}
Atteststion Key {{ template "tpm2key.html" .AK }}
Device {{ .Device }}
EKCert {{ .EKCertHandle }}
EK + {{ .EK.Handle }}
AK + {{ .AK.Handle }}
-{{end}} - - +{{end}} \ No newline at end of file diff --git a/janeserver/services/webui/templates/tpm2key.html b/janeserver/services/webui/templates/tpm2key.html index 96e8ae5..cfb30ef 100644 --- a/janeserver/services/webui/templates/tpm2key.html +++ b/janeserver/services/webui/templates/tpm2key.html @@ -2,7 +2,8 @@ - + +
Handle {{ .Handle }}
Public {{ .Public }}
Public {{ .Public }}
Name {{ .Name }}
{{end}} diff --git a/janeserver/services/x3270/initx3270.go b/janeserver/services/x3270/initx3270.go index 0561f09..59bdfa2 100644 --- a/janeserver/services/x3270/initx3270.go +++ b/janeserver/services/x3270/initx3270.go @@ -1,11 +1,11 @@ package x3270 import ( - _ "net/http" - + "context" "fmt" "net" "os" + "time" "a10/configuration" "a10/logging" @@ -18,34 +18,61 @@ func init() { go3270.Debug = os.Stderr } -func StartX3270() { - - //get configuration data +func StartX3270(ctx context.Context) { port := configuration.ConfigData.X3270.Port - //crt := configuration.ConfigData.Rest.Crt - //key:= configuration.ConfigData.Rest.Key - //usehttp := configuration.ConfigData.Rest.UseHTTP + + fmt.Println(" -> 3270 starting") //start the server - ln, err := net.Listen("tcp", ":"+port) + listener, err := net.Listen("tcp", ":"+port) if err != nil { - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 service failed to start.") - fmt.Printf("X3270 failed to start service") - panic(err) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 service listener failed to start: "+err.Error()) + fmt.Printf("X3270 service listener failed to start: %v\n", err.Error()) + return + } + + tcpListener, ok := listener.(*net.TCPListener) + if !ok { + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 tcp assertion failed: "+err.Error()) + fmt.Printf("X3270 tcp assertion failed: %v\n", err.Error()) + return } - logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 service started.") - fmt.Printf("X3270 service listening on port %v\n", port) + // Set a deadline for the Accept() call + deadline := time.Now().Add(10 * time.Second) + if err := tcpListener.SetDeadline(deadline); err != nil { + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 setting deadline failed: "+err.Error()) + fmt.Printf("X3270 setting deadline failed: %v\n", err.Error()) + return + } + + msg := fmt.Sprintf("X3270 service started on port %v", port) + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", msg) + + go func() { + <-ctx.Done() + tcpListener.Close() + }() + for { - conn, err := ln.Accept() - if err != nil { - logging.MakeLogEntry("SYS", "x3270", configuration.ConfigData.System.Name, "JANE", "X3270 failed to accept connnection") - fmt.Printf("X3270 failed to accept connnection") - panic(err) + select { + default: + conn, err := tcpListener.Accept() + if err != nil { + //fmt.Println("An error occured:", err.Error(), " Will reset timeout deadline anyway") + deadline = time.Now().Add(10 * time.Second) + tcpListener.SetDeadline(deadline) + } else { + //fmt.Println("Accepting a connection") + go func() { handle(conn) }() + } + case <-ctx.Done(): + //fmt.Println("X3270 DONE SIGNAL RECEIVED") + msg := fmt.Sprintf("X3270 graceful shutdown") + logging.MakeLogEntry("SYS", "shutdown", configuration.ConfigData.System.Name, "X3270", msg) + return } - go handle(conn) } - } // handle is the handler for individual user connections. @@ -67,7 +94,7 @@ func handle(conn net.Conn) { 4, 20, // the row and column to place the cursor conn) if err != nil { - fmt.Printf("X3270 handle screen error %w", err) + fmt.Printf("X3270 handle screen error %v\n", err.Error()) fmt.Println(err) return } diff --git a/janeserver/services/x3270/initx3270.old b/janeserver/services/x3270/initx3270.old new file mode 100644 index 0000000..6bf870a --- /dev/null +++ b/janeserver/services/x3270/initx3270.old @@ -0,0 +1,71 @@ +package x3270 + +import ( + "fmt" + "net" + "os" + + "a10/configuration" + "a10/logging" + + "github.com/racingmars/go3270" + + "context" +) + +func init() { + // put the go3270 library in debug mode + go3270.Debug = os.Stderr +} + +func StartX3270(ctx context.Context) { + fmt.Printf("X3270 context %v\n", ctx) + + //get configuration data + port := configuration.ConfigData.X3270.Port + + //start the server + ln, err := net.Listen("tcp", ":"+port) + if err != nil { + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 service failed to start: "+err.Error()) + fmt.Printf("X3270 failed to start service: %v\n", err.Error()) + return + } + + logging.MakeLogEntry("SYS", "startup", configuration.ConfigData.System.Name, "JANE", "X3270 service started.") + fmt.Printf("X3270 service listening on port %v\n", port) + for { + conn, err := ln.Accept() + if err != nil { + logging.MakeLogEntry("SYS", "x3270", configuration.ConfigData.System.Name, "JANE", "X3270 failed to accept connnection: "+err.Error()) + fmt.Printf("X3270 failed to accept connnection: %v\n", err.Error()) + } + go handle(conn) + } +} + +// handle is the handler for individual user connections. +func handle(conn net.Conn) { + defer conn.Close() + + // Always begin new connection by negotiating the telnet options + go3270.NegotiateTelnet(conn) + + fieldValues := make(map[string]string) + + response, err := go3270.HandleScreen( + titlescreen, // the screen to display + titlescreenrules, // the rules to enforce + fieldValues, // any field values we wish to supply + []go3270.AID{go3270.AIDEnter}, // the AID keys we support + []go3270.AID{go3270.AIDPF3}, // keys that are "exit" keys + "errormsg", // the field to write error message into + 4, 20, // the row and column to place the cursor + conn) + if err != nil { + fmt.Printf("X3270 handle screen error %v\n", err.Error()) + return + } + + fmt.Printf("Connection closed %v \n", response) +} diff --git a/janeserver/structures/claims.go b/janeserver/structures/claims.go index dd3b5f2..4ab80f4 100644 --- a/janeserver/structures/claims.go +++ b/janeserver/structures/claims.go @@ -1,30 +1,32 @@ package structures type Claim struct { - ItemID string `json:"itemid",bson:"itemid"` - BodyType string `json:"bodytype",bson:"bodytype"` - Header ClaimHeader `json:"header",bson:"header"` - Body map[string]interface{} `json:"body",bson:"body"` - Footer ClaimFooter `json:"footer",bson:"footer"` + ItemID string `json:"itemid" bson:"itemid"` + BodyType string `json:"bodytype" bson:"bodytype"` + Header ClaimHeader `json:"header" bson:"header"` + Body map[string]interface{} `json:"body" bson:"body"` + Footer ClaimFooter `json:"footer" bson:"footer"` } type ClaimHeader struct { - Element Element `json:"element",bson:"element"` - Intent Intent `json:"intent",bson:"intent"` - Session Session `json:"session",bson:"session"` - Timing Timing `json:"timing",bson:"timing"` - AdditionalParameters map[string]interface{} `json:"aps",bson:"aps"` - CallParameters map[string]interface{} `json:"cps",bson:"cps"` + Element Element `json:"element" bson:"element"` + Intent Intent `json:"intent" bson:"intent"` + EndpointName string `json:"endpointname" bson:"endpointname"` + Endpoint Endpoint `json:"endpoint" bson:"endpoint"` + Session Session `json:"session" bson:"session"` + Timing Timing `json:"timing" bson:"timing"` + AdditionalParameters map[string]interface{} `json:"aps" bson:"aps"` + CallParameters map[string]interface{} `json:"cps" bson:"cps"` } type Timing struct { - Requested Timestamp `json:"requested",bson:"requested"` - Received Timestamp `json:"received",bson:"received"` + Requested Timestamp `json:"requested" bson:"requested"` + Received Timestamp `json:"received" bson:"received"` } type ClaimFooter struct { - Hash []byte `json:"hash",bson:"hash"` - Signature []byte `json:"signature",bson:"signature"` + Hash []byte `json:"hash" bson:"hash"` + Signature []byte `json:"signature" bson:"signature"` } const CLAIMERROR = "*ERROR" diff --git a/janeserver/structures/common.go b/janeserver/structures/common.go index d29b405..8ce3c2d 100644 --- a/janeserver/structures/common.go +++ b/janeserver/structures/common.go @@ -1,5 +1,5 @@ package structures type ID struct { - ItemID string `json:"itemid",bson:"itemid"` + ItemID string `json:"itemid" bson:"itemid"` } diff --git a/janeserver/structures/elements.go b/janeserver/structures/elements.go index e46bda9..7389b5e 100644 --- a/janeserver/structures/elements.go +++ b/janeserver/structures/elements.go @@ -1,66 +1,85 @@ package structures type Element struct { - ItemID string `json:"itemid,omitempty",bson:"itemid,omitempty"` - Name string `json:"name",bson:"name"` - Description string `json:"description",bson:"description"` - Endpoint string `json:"endpoint",bson:"endpoint"` - Protocol string `json:"protocol",bson:"protocol"` - Tags []string `json:"tags",bson:"tags"` - - Sshkey SSHKEY `json:"sshkey,omitempty",bson:"sshkey,omitempty"` - TPM2 TPM2 `json:"tpm2,omitempty",bson:"tpm2,omitempty"` - UEFI UEFI `json:"uefi,omitempty",bson:"uefi,omitempty"` - IMA IMA `json:"ima,omitempty",bson:"ima,omitempty"` - TXT TXT `json:"txt,omitempty",bson:"txt,omitempty"` - Host HostMachine `json:"host,omitempty",bson:"host,omitempty"` - MRCoordinator MRCoordinator `json:"mrcoordinator,omitempty" bson:"mrcoordinator,omitempty"` - MRMarbleInstance MRMarbleInstance `json:"mrmarbleinstance,omitempty" bson:"mrmarbleinstance,omitempty"` + ItemID string `json:"itemid,omitempty" bson:"itemid,omitempty" yaml:"itemid,omitempty"` + Name string `json:"name" bson:"name" yaml:"name"` + Description string `json:"description" bson:"description" yaml:"description"` + + // endpoints, map a name to a string containing the URL - this allows multiple endpoints for a single + // element, supporting multiple protocols + Endpoints map[string]Endpoint `json:"endpoints" bson:"endpoints" yaml:"endpoints"` + + Tags []string `json:"tags" bson:"tags" yaml:"tags"` + + Sshkey SSHKEY `json:"sshkey,omitempty" bson:"sshkey,omitempty" yaml:"sshkey,omitempty"` + TPM2 TPM2 `json:"tpm2,omitempty" bson:"tpm2,omitempty" yaml:"tpm2,omitempty"` + UEFI UEFI `json:"uefi,omitempty" bson:"uefi,omitempty" yaml:"uefi,omitempty"` + IMA IMA `json:"ima,omitempty" bson:"ima,omitempty" yaml:"ima,omitempty"` + TXT TXT `json:"txt,omitempty" bson:"txt,omitempty" yaml:"txt,omitempty"` + Host HostMachine `json:"host,omitempty" bson:"host,omitempty" yaml:"host,omitempty"` + MRCoordinator MRCoordinator `json:"mrcoordinator,omitempty" bson:"mrcoordinator,omitempty" yaml:"mrcoordinator,omitempty"` + MRMarbleInstance MRMarbleInstance `json:"mrmarbleinstance,omitempty" bson:"mrmarbleinstance,omitempty" yaml:"mrmarbleinstance,omitempty"` + + RecordHistory RecordHistory `json:"recordhistory,omitempty" bson:"recordhistory,omitempty" yaml:"recordhistory,omitempty"` +} + +// ELEMENTSUMMARY MUST BE A SUBSET OF THE ELEMENT TYPE +type ElementSummary struct { + ItemID string `json:"itemid,omitempty" bson:"itemid,omitempty" yaml:"itemid,omitempty"` + Name string `json:"name" bson:"name" yaml:"name"` + Endpoints map[string]Endpoint `json:"endpoints" bson:"endpoints" yaml:"endpoints"` +} + +type Endpoint struct { + Endpoint string `json:"endpoint" bson:"endpoint" yaml:"endpoint"` + Protocol string `json:"protocol" bson:"protocol" yaml:"protocol"` } type HostMachine struct { - OS string `json:"os",bson:"os"` - Arch string `json:"arch",bson:"arch"` - Hostname string `json:"hostname",bson:"hostname"` + OS string `json:"os" bson:"os" yaml:"os"` + Arch string `json:"arch" bson:"arch" yaml:"arch"` + Hostname string `json:"hostname" bson:"hostname" yaml:"hostname"` + MachineID string `json:"machineid" bson:"machineid" yaml:"machineid"` } type SSHKEY struct { - Key string `json:"key",bson:"key"` - Timeout int16 `json:"timeout",bson:"timeout"` - Username string `json:"username",bson:"username"` + Key string `json:"key" bson:"key" yaml:"key"` + Timeout int16 `json:"timeout" bson:"timeout" yaml:"timeout"` + Username string `json:"username" bson:"username" yaml:"username"` } type UEFI struct { - Eventlog string `json:"eventlog",bson:"eventlog"` + Eventlog string `json:"eventlog" bson:"eventlog" yaml:"eventlog"` } type IMA struct { - ASCIILog string `json:"asciilog",bson:"asciilog"` + ASCIILog string `json:"asciilog" bson:"asciilog" yaml:"asciilog"` } type TXT struct { - Log string `json:"log",bson:"log"` + Log string `json:"log" bson:"log" yaml:"log"` } type TPM2 struct { - Device string `json:"device",bson:"device"` - EKCertHandle string `json:"ekcerthandle",bson:"ekcerthandle"` - EK TPMKey `json:"ek",bson:"ek"` - AK TPMKey `json:"ak",bson:"ak"` + Device string `json:"device" bson:"device" yaml:"device"` + EKCertHandle string `json:"ekcerthandle" bson:"ekcerthandle" yaml:"ekcerthandle"` + EK TPMKey `json:"ek" bson:"ek" yaml:"ek"` + AK TPMKey `json:"ak" bson:"ak" yaml:"ak"` } type TPMKey struct { - Handle string `json:"handle",bson:"handle"` + Handle string `json:"handle" bson:"handle" yaml:"handle"` // Public portion of the key marshalled as TPM2BPublic - Public string `json:"public",bson:"public"` + Public string `json:"public" bson:"public" yaml:"public"` + Name string `json:"name" bson:"name" yaml:"name"` } type MRCoordinator struct { - Certs []string `json:"certs" bson:"certs"` + Certs []string `json:"certs" bson:"certs" yaml:"certs"` } type MRMarbleInstance struct { - ExpectedNonce string `json:"expectednonce" bson:"expectednonce"` - RequestData string `json:"requestdata" bson:"requestdata"` - RequestSignature string `json:"requestsignature" bson:"requestsignature"` + ExpectedNonce string `json:"expectednonce" bson:"expectednonce" yaml:"expectednonce"` + RequestData string `json:"requestdata" bson:"requestdata" yaml:"requestdata"` + RequestSignature string `json:"requestsignature" bson:"requestsignature" yaml:"requestsignature"` } diff --git a/janeserver/structures/expectedValues.go b/janeserver/structures/expectedValues.go index ccc80a1..2153ebf 100644 --- a/janeserver/structures/expectedValues.go +++ b/janeserver/structures/expectedValues.go @@ -8,14 +8,17 @@ import ( ) type ExpectedValue struct { - ItemID string `json:"itemid",bson:"itemid"` - Name string `json:"name",bson:"name"` - Description string `json:"description",bson:"description"` + ItemID string `json:"itemid" bson:"itemid"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` - ElementID string `json:"elementid",bson:"elementid"` - IntentID string `json:"intentid",bson:"intentid"` + ElementID string `json:"elementid" bson:"elementid"` + EndpointName string `json:"endpointname" bson:"endpointname"` + IntentID string `json:"intentid" bson:"intentid"` - EVS map[string]interface{} `json:"evs",bson:"evs"` + EVS map[string]interface{} `json:"evs" bson:"evs"` + + RecordHistory RecordHistory `json:"recordhistory,omitempty" bson:"recordhistory,omitempty" yaml:"recordhistory,omitempty"` } type KeylimeMBEV struct { diff --git a/janeserver/structures/intents.go b/janeserver/structures/intents.go index 3542bc8..80bf753 100644 --- a/janeserver/structures/intents.go +++ b/janeserver/structures/intents.go @@ -1,9 +1,9 @@ package structures type Intent struct { - ItemID string `json:"itemid",bson:"itemid"` - Name string `json:"name",bson:"name"` - Description string `json:"description",bson:"description"` - Function string `json:"function",bson:"function"` - Parameters map[string]interface{} `json:"parameters",bson:"parameters"` + ItemID string `json:"itemid" bson:"itemid"` + Name string `json:"name" bson:"name"` + Description string `json:"description" bson:"description"` + Function string `json:"function" bson:"function"` + Parameters map[string]interface{} `json:"parameters" bson:"parameters"` } diff --git a/janeserver/structures/logs.go b/janeserver/structures/logs.go index b63cf21..e0af01a 100644 --- a/janeserver/structures/logs.go +++ b/janeserver/structures/logs.go @@ -1,12 +1,12 @@ package structures type LogEntry struct { - ItemID string `json:"itemid",bson:"itemid"` - Timestamp Timestamp `json:"timestamp",bson:"timestamp"` - Channel string `json:"channel",bson:"channel"` - Operation string `json:"operation",bson:"operation"` - RefID string `json:"refid",bson:"refid"` - RefType string `json:"reftype",bson:"reftype"` - Message string `json:"message",bson:"message"` - Hash []byte `json:"hash",bson:"hash"` + ItemID string `json:"itemid" bson:"itemid"` + Timestamp Timestamp `json:"timestamp" bson:"timestamp"` + Channel string `json:"channel" bson:"channel"` + Operation string `json:"operation" bson:"operation"` + RefID string `json:"refid" bson:"refid"` + RefType string `json:"reftype" bson:"reftype"` + Message string `json:"message" bson:"message"` + Hash []byte `json:"hash" bson:"hash"` } diff --git a/janeserver/structures/messages.go b/janeserver/structures/messages.go new file mode 100644 index 0000000..99bcd9f --- /dev/null +++ b/janeserver/structures/messages.go @@ -0,0 +1,9 @@ +package structures + +type Message struct { + ItemID string `json:"itemid" bson:"itemid" yaml:"itemid"` + SessionID string `json:"sessionid" bson:"sessionid" yaml:"sessionid"` + ElementID string `json:"elementid" bson:"elementid" yaml:"elementid"` + Contents string `json:"contents" bson:"contents" yaml:"contents"` + Timestamp Timestamp `json:"timestamp" bson:"timestamp"` +} diff --git a/janeserver/structures/opaqueobjects.go b/janeserver/structures/opaqueobjects.go index 55f091e..18e3873 100644 --- a/janeserver/structures/opaqueobjects.go +++ b/janeserver/structures/opaqueobjects.go @@ -1,8 +1,8 @@ package structures type OpaqueObject struct { - Value string `json:"value",bson:"value"` - Type string `json:"type",bson:"type"` - ShortDescription string `json:"shortdescription",bson:"shortdescription"` - LongDescription string `json:"longdescription",bson:"longdescription"` + Value string `json:"value" bson:"value"` + Type string `json:"type" bson:"type"` + ShortDescription string `json:"shortdescription" bson:"shortdescription"` + LongDescription string `json:"longdescription" bson:"longdescription"` } diff --git a/janeserver/structures/protocols.go b/janeserver/structures/protocols.go index d2d8bcd..9101fb7 100644 --- a/janeserver/structures/protocols.go +++ b/janeserver/structures/protocols.go @@ -4,7 +4,7 @@ package structures // // In useage it takes the element, policy, session and a "json" structure of parameters // Return is "json" and a string containing any error messages -type ProtocolCall func(Element, Intent, Session, map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) +type ProtocolCall func(Element, Endpoint, Intent, Session, map[string]interface{}) (map[string]interface{}, map[string]interface{}, string) type Protocol struct { Name string diff --git a/janeserver/structures/recordhistory.go b/janeserver/structures/recordhistory.go new file mode 100644 index 0000000..ab36754 --- /dev/null +++ b/janeserver/structures/recordhistory.go @@ -0,0 +1,8 @@ +package structures + +type RecordHistory struct { + Created Timestamp `json:"created,omitempty" bson:"created,omitempty"` + LastUpdated Timestamp `json:"lastupdated,omitempty" bson:"lastupdated,omitempty"` + Archived Timestamp `json:"archived,omitempty" bson:"archived,omitempty"` + Reason string `json:"reason" bson:"reason"` +} diff --git a/janeserver/structures/results.go b/janeserver/structures/results.go index 6b64c5f..a846d76 100644 --- a/janeserver/structures/results.go +++ b/janeserver/structures/results.go @@ -16,21 +16,21 @@ const ( ) type Result struct { - ItemID string `json:"itemid",bson:"itemid"` - ClaimID string `json:"claimid",bson:"claimid"` - ClaimFooter ClaimFooter `json:"claimfooter",bson:"claimfooter"` - Session Session `json:"session",bson:"session"` - ElementID string `json:"elementid",bson:"elementid"` - ExpectedValue ExpectedValue `json:"expectedvalue",bson:"expectedvalue"` - Parameters map[string]interface{} `json:"parameters",bson:"parameters"` - Message string `json:"message",bson:"message"` - RuleName string `json:"rulename",bson:"rulename"` - VerifiedAt Timestamp `json:"verifiedat",bson:"verifiedat"` - Result ResultValue `json:"result",bson:"result"` - Footer ResultFooter `json:"footer",bson:"footer"` + ItemID string `json:"itemid" bson:"itemid"` + ClaimID string `json:"claimid" bson:"claimid"` + ClaimFooter ClaimFooter `json:"claimfooter" bson:"claimfooter"` + Session Session `json:"session" bson:"session"` + ElementID string `json:"elementid" bson:"elementid"` + ExpectedValue ExpectedValue `json:"expectedvalue" bson:"expectedvalue"` + Parameters map[string]interface{} `json:"parameters" bson:"parameters"` + Message string `json:"message" bson:"message"` + RuleName string `json:"rulename" bson:"rulename"` + VerifiedAt Timestamp `json:"verifiedat" bson:"verifiedat"` + Result ResultValue `json:"result" bson:"result"` + Footer ResultFooter `json:"footer" bson:"footer"` } type ResultFooter struct { - Hash []byte `json:"hash",bson:"hash"` - Signature []byte `json:"signature",bson:"signature"` + Hash []byte `json:"hash" bson:"hash"` + Signature []byte `json:"signature" bson:"signature"` } diff --git a/janeserver/structures/sessions.go b/janeserver/structures/sessions.go index 77c2efe..766a83d 100644 --- a/janeserver/structures/sessions.go +++ b/janeserver/structures/sessions.go @@ -1,28 +1,28 @@ package structures type Session struct { - ItemID string `json:"itemid",bson:"itemid"` - Timing SessionTiming `json:"timing",bson:"timing"` + ItemID string `json:"itemid" bson:"itemid"` + Timing SessionTiming `json:"timing" bson:"timing"` - ClaimList []string `json:"claimlist",bson:"claimlist"` - ResultList []string `json:"resultlist",bson:"resultlist"` + ClaimList []string `json:"claimlist" bson:"claimlist"` + ResultList []string `json:"resultlist" bson:"resultlist"` - Message string `json:"message",bson:"message"` + Message string `json:"message" bson:"message"` - Footer SessionFooter `json:"footer",bson:"footer"` + Footer SessionFooter `json:"footer" bson:"footer"` } type SessionSummary struct { - ItemID string `json:"itemid",bson:"itemid"` - Timing SessionTiming `json:"timing",bson:"timing"` + ItemID string `json:"itemid" bson:"itemid"` + Timing SessionTiming `json:"timing" bson:"timing"` } type SessionTiming struct { - Opened Timestamp `json:"opened",bson:"opened"` - Closed Timestamp `json:"closed",bson:"closed"` + Opened Timestamp `json:"opened" bson:"opened"` + Closed Timestamp `json:"closed" bson:"closed"` } type SessionFooter struct { - Hash []byte `json:"hash",bson:"hash"` - Signature []byte `json:"signature",bson:"signature"` + Hash []byte `json:"hash" bson:"hash"` + Signature []byte `json:"signature" bson:"signature"` } diff --git a/janeserver/utilities/endpoints.go b/janeserver/utilities/endpoints.go new file mode 100644 index 0000000..b15290f --- /dev/null +++ b/janeserver/utilities/endpoints.go @@ -0,0 +1,13 @@ +package utilities + +import ( + "a10/structures" +) + +func SelectEndpoint(e structures.Element, epn string) (structures.Endpoint, bool) { + + eps := e.Endpoints + ep, ok := eps[epn] + + return ep, ok +} diff --git a/janeserver/utilities/timestamps.go b/janeserver/utilities/timestamps.go index 3711a35..47c3af7 100644 --- a/janeserver/utilities/timestamps.go +++ b/janeserver/utilities/timestamps.go @@ -2,14 +2,12 @@ package utilities import ( "time" - //"fmt" "a10/structures" ) // makeTimestamp generates the number of nanoseconds since Unix Epoch in UTC. func MakeTimestamp() structures.Timestamp { - //t := structures.Timestamp(fmt.Sprintf("%d",time.Now().UnixNano())) t := structures.Timestamp(time.Now().UnixNano()) return t @@ -23,7 +21,6 @@ func TimeStampHoursAgo(d string) structures.Timestamp { if err != nil { xdur, _ := time.ParseDuration("1h") - //return structures.Timestamp(fmt.Sprintf("%d",now-xdur.Nanoseconds())) return structures.Timestamp(now - xdur.Nanoseconds()) } else { diff --git a/provisioner/__init__.py b/provisioner/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/provisioner/__main__.py b/provisioner/__main__.py new file mode 100644 index 0000000..11eaba9 --- /dev/null +++ b/provisioner/__main__.py @@ -0,0 +1,9 @@ +#!/bin/python3 +from jp import runjp + +def runprovisioner(): + print("Running provisioner") + runjp() + +if __name__ == "__main__": + runprovisioner() \ No newline at end of file diff --git a/provisioner/bin/Activate.ps1 b/provisioner/bin/Activate.ps1 new file mode 100644 index 0000000..16ba529 --- /dev/null +++ b/provisioner/bin/Activate.ps1 @@ -0,0 +1,248 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +$env:VIRTUAL_ENV_PROMPT = $Prompt + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/provisioner/bin/activate b/provisioner/bin/activate new file mode 100644 index 0000000..b72147e --- /dev/null +++ b/provisioner/bin/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# You cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past locations. Without forgetting + # past locations the $PATH changes we made may not be respected. + # See "man bash" for more details. hash is usually a builtin of your shell + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +# on Windows, a path can contain colons and backslashes and has to be converted: +case "$(uname)" in + CYGWIN*|MSYS*|MINGW*) + # transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW + # and to /cygdrive/d/path/to/venv on Cygwin + VIRTUAL_ENV=$(cygpath /home/ian/jane/provisioner) + export VIRTUAL_ENV + ;; + *) + # use the path as-is + export VIRTUAL_ENV=/home/ian/jane/provisioner + ;; +esac + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/"bin":$PATH" +export PATH + +VIRTUAL_ENV_PROMPT=provisioner +export VIRTUAL_ENV_PROMPT + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="("provisioner") ${PS1:-}" + export PS1 +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/provisioner/bin/activate.csh b/provisioner/bin/activate.csh new file mode 100644 index 0000000..81ae7a4 --- /dev/null +++ b/provisioner/bin/activate.csh @@ -0,0 +1,27 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. + +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV /home/ian/jane/provisioner + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/"bin":$PATH" +setenv VIRTUAL_ENV_PROMPT provisioner + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "("provisioner") $prompt:q" +endif + +alias pydoc python -m pydoc + +rehash diff --git a/provisioner/bin/activate.fish b/provisioner/bin/activate.fish new file mode 100644 index 0000000..71b4eb9 --- /dev/null +++ b/provisioner/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV /home/ian/jane/provisioner + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/"bin $PATH +set -gx VIRTUAL_ENV_PROMPT provisioner + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s(%s)%s " (set_color 4B8BBE) provisioner (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/provisioner/bin/normalizer b/provisioner/bin/normalizer new file mode 100755 index 0000000..aab17e1 --- /dev/null +++ b/provisioner/bin/normalizer @@ -0,0 +1,8 @@ +#!/home/ian/jane/provisioner/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from charset_normalizer.cli import cli_detect +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli_detect()) diff --git a/provisioner/bin/pip b/provisioner/bin/pip new file mode 100755 index 0000000..43c80dd --- /dev/null +++ b/provisioner/bin/pip @@ -0,0 +1,8 @@ +#!/home/ian/jane/provisioner/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/provisioner/bin/pip3 b/provisioner/bin/pip3 new file mode 100755 index 0000000..43c80dd --- /dev/null +++ b/provisioner/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/ian/jane/provisioner/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/provisioner/bin/pip3.11 b/provisioner/bin/pip3.11 new file mode 100755 index 0000000..43c80dd --- /dev/null +++ b/provisioner/bin/pip3.11 @@ -0,0 +1,8 @@ +#!/home/ian/jane/provisioner/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/provisioner/bin/python b/provisioner/bin/python new file mode 100755 index 0000000..528ad50 Binary files /dev/null and b/provisioner/bin/python differ diff --git a/provisioner/bin/python3 b/provisioner/bin/python3 new file mode 100755 index 0000000..6ff6dcf Binary files /dev/null and b/provisioner/bin/python3 differ diff --git a/provisioner/bin/python3.11 b/provisioner/bin/python3.11 new file mode 100755 index 0000000..528ad50 Binary files /dev/null and b/provisioner/bin/python3.11 differ diff --git a/provisioner/examplecreateprovisioningfile.yaml b/provisioner/examplecreateprovisioningfile.yaml new file mode 100644 index 0000000..5a3e398 --- /dev/null +++ b/provisioner/examplecreateprovisioningfile.yaml @@ -0,0 +1,79 @@ +#A Sample Provisioning File + +attestationserver: http://127.0.0.1:8520 +element: + name: Debian13VM + description: Debian 13 VM + tags: + - linux + - x86 + - tpm2 + - uefi + - vbox +endpoints: + tarzan: + endpoint: http://127.0.0.1:8530 + protocol: A10HTTPRESTv2 + ratds: + endpoint: http://127.0.0.1:8531 + protocol: RATSD +tpm2: + device: /dev/tpmrm0 + ekcerthandle: '0x1C000002' + ek: + handle: '0x810100EE' + ak: + handle: '0x810100AA' +provisionworklist: + - tpmclear + - tpmprovision + - collecthostinfo + - collecttpm2 + - collectuefi + - collectima + - makebetterdescription + - processelement +# - processevs + - processevs_withrules + +evs: + - std::intent::sys::info : + protocol: tarzan + type: sysmachineid + rules: + - sys_taRunningSafely + - sys_machineID_Agent + - sys_machineID_CrossRef + - std::intent::sha256::crtm::pcr0 : + protocol: tarzan + type: tpm2quote + rules: + - tpm2_attestedValue + - tpm2_firmware + - tpm2_magicNumber + - tpm2_safe + - tpm2_validNonce + - std::intent::sha256::crtm::firmware : + protocol: tarzan + type: tpm2quote + rules: + - tpm2_attestedValue + - tpm2_firmware + - tpm2_magicNumber + - tpm2_safe + - tpm2_validNonce + - std::intent::sha256::crtm::bootloaderonly : + protocol: tarzan + type: tpm2quote + rules: + - tpm2_attestedValue + - tpm2_firmware + - tpm2_magicNumber + - tpm2_safe + - tpm2_validNonce + - std::intent::linux::ima::asciilog : + protocol: tarzan + - std::intent::tpm::pcrs : + protocol: tarzan + - std::intent::uefi::efivars : + protocol: tarzan diff --git a/provisioner/jp.py b/provisioner/jp.py new file mode 100755 index 0000000..482389d --- /dev/null +++ b/provisioner/jp.py @@ -0,0 +1,349 @@ +import sys +import pathlib +import yaml +import platform +import socket +import requests +import subprocess +import datetime +import argparse + + +# +# Global + +safemode=True + +# +# +# TPM Functions +# + +def callcmd(cmd): + print("Calling: ",cmd) + result = subprocess.run(cmd, capture_output=True, text=True) + print(" ! ",result) + +def tpmclear(pdata): + # gets the EK and AK values then removes them from the TPM + ek = str(pdata["tpm2"]["ek"]["handle"]) + ak = str(pdata["tpm2"]["ak"]["handle"]) + print("ek,ak",ek,ak) + + cmd1=["/usr/bin/tpm2_evictcontrol","-c",ek] + cmd2=["/usr/bin/tpm2_evictcontrol","-c",ak] + + callcmd(cmd1) + callcmd(cmd2) + +def tpmprovision(pdata): + ek = str(pdata["tpm2"]["ek"]["handle"]) + ak = str(pdata["tpm2"]["ak"]["handle"]) + print("ek,ak",ek,ak) + + + cmd1=["/usr/bin/tpm2_createek","-c", ek, "-G", "rsa", "-u", "/tmp/ek.pub"] + cmd2=["/usr/bin/tpm2_createak","-C", ek ,"-c","/tmp/ak.ctx","-G","rsa","-g","sha256","-s","rsassa","-u","/tmp/ak.pub","-f","pem","-n","/tmp/ak.name"] + cmd3=["/usr/bin/tpm2_evictcontrol","-c","/tmp/ak.ctx", ak] + cmd4=["/usr/bin/tpm2_getcap","handles-persistent"] + + callcmd(cmd1) + callcmd(cmd2) + callcmd(cmd3) + callcmd(cmd4) + +# +# Functions +# + +def openSession(url): + jurl = url+"/session" + msg="Provisioning Session" + r = requests.post(jurl, json={"message":msg}) + print("session is",r.json()["itemid"]) + return r.json()["itemid"] + +def closeSession(url,sid): + jurl = url+"/session/"+sid + r = requests.delete(jurl) + print("session close",r.status_code) + +def runrules(url,rs,sid,cid): + for r in rs: + print(" ... ... ",r) + rurl = url+"/verify" + u = requests.post(rurl,json={ "cid":cid, "sid":sid, "rule":r}) + print(" ... ... ... ",u.status_code) + + +def processevs(pdata,eid,cmd,rr): + jurl = pdata["attestationserver"]+"/element" + + #need to open session here + sid = openSession(pdata["attestationserver"]) + for e in pdata["evs"]: + pid = list(e.keys())[0] + epn = e[pid]["protocol"] + print(eid,pid,epn,sid) + + aurl = pdata["attestationserver"]+"/attest" + adata = { "eid":eid,"pid":pid,"epn":epn,"sid":sid,"parameters":{}} + r = requests.post(aurl, json=adata) + print(" ... attest ... ",r.status_code) + cid = r.json()["itemid"] + curl = pdata["attestationserver"]+"/claim/"+cid + c = requests.get(curl) + print(" ... claim ... ",c.status_code,cid) + + # if there is a type field then process the result to create an EVS + + if "type" in e[pid].keys(): + processexpectedvaluetypes(e,pid,eid,epn,c,pdata,cmd) + + + if rr==True: + if "rules" in e[pid].keys(): + runrules(pdata["attestationserver"],e[pid]["rules"],sid,cid) + + closeSession(pdata["attestationserver"],sid) + + +def processexpectedvaluetypes(e,pid,eid,epn,c,pdata,cmd): + if e[pid]["type"]=="sysmachineid": + cb = c.json() + d = pdata['element']['name']+"---"+e[pid]["type"]+" at "+timenow()+" UTC" + n = pdata['element']['name']+"---"+pid + evs = {"name":n,"description":d,"evs":{"machineid":cb["body"]["machineid"]},"elementid":eid,"intentid":pid,"endpointname":epn} + print(evs) + createupdateEVS(pdata,evs,eid,pid,epn,cmd) + + if e[pid]["type"]=="tpm2quote": + q = c.json() + print("*********************") + print(q["body"]["quote"]["attested"]["pcrdigest"]) + print(q["body"]["quote"]["firmwareVersion"]) + print("*********************") + + d = pdata['element']['name']+"---"+e[pid]["type"]+" at "+timenow()+" UTC" + n = pdata['element']['name']+"---"+pid + evs = {"name":n+"-"+pid,"description": d, + "evs":{"attestedValue":q["body"]["quote"]["attested"]["pcrdigest"], + "firmwareVersion":q["body"]["quote"]["firmwareVersion"]}, + "elementid":eid,"intentid":pid,"endpointname":epn} + createupdateEVS(pdata,evs,eid,pid,epn,cmd) + +def createupdateEVS(pdata,evs,eid,pid,epn,cmd): + evsurl = pdata["attestationserver"]+"/expectedValue" + + evsid=getEVSID(pdata,eid,pid,epn) + + if evsid!='x': + print(" ... updating evs...",evsid) + evs["itemid"]=evsid + t = requests.put(evsurl, json=evs) + else: + print(" ... creating evs") + t = requests.post(evsurl, json=evs) + print(" ... evs ... ",t.status_code,t.json()) + +def getEVSID(pdata,eid,pid,epn): + jurl = pdata["attestationserver"]+"/expectedValue/"+eid+"/"+pid+"/"+epn + print(" ... evs, checking:",jurl) + r = requests.get(jurl) + print(" ... status ",r.status_code) + evs = r.json() + if r.status_code!=200: + return "x" + print(" ... evs",evs["itemid"]) + return evs["itemid"] + +def processelement(pdata, e, cmd): + jurl = pdata["attestationserver"]+"/element" + + if cmd=="create": + print("creating...") + r = requests.post(jurl, json=e) + elif cmd=="update": + eid=getIDfile() + print("updating element...",eid) + e["itemid"]=eid + r = requests.put(jurl, json=e) + else: + print("Unknown processelement command, I do not understand what is",cmd) + + print("Result is",r.status_code,r.reason,r.json()) + + i = r.json()["itemid"] + return i + +def collectuefi(): + return "/sys/kernel/security/tpm0/binary_bios_measurements" + +def collectima(): + return "/sys/kernel/security/ima/ascii_runtime_measurements" + + +def collecthostinfo(): + p = platform.platform() + a = platform.machine() + h = socket.gethostname() + m = "" + + f = open("/etc/machine-id","r") + m = f.readlines()[0].strip() + + r = { "os":p, "arch":a, "hostname":h, "machineid":m } + return r + +def intialiseElementStructure(pdata): + e={} + e['name']=pdata['element']['name'] + e['description']=pdata['element']['description'] + e['tags']=pdata['element']['tags'] + e['endpoints']=pdata['endpoints'] + + return e + +def makebetterdescription(pdata): + d="" + d = pdata['element']['description'] + d = d + "Element name: ("+pdata['element']['name']+") " + d = d + "Entry added at "+timenow()+" UTC" + return d + +def timenow(): + return str(datetime.datetime.now(datetime.timezone.utc)) + + +def writeIDtoFile(i): + # this writes the itemID to a file /etc/janeelementid + with open("/etc/janeelementid","w") as f: + f.write(i) + +def getIDfile(): + # the reads the janeelementid file + with open("/etc/janeelementid","r") as f: + c = f.read().splitlines() + return c[0] + +def IDfileExists(): + f = pathlib.Path("/etc/janeelementid") + return f.is_file() + +# +# Worklist +# + +def processWorklist(pdata,cmd): + e=intialiseElementStructure(pdata) + i="" + + for w in pdata['provisionworklist']: + if (w=='tpmclear'): + if continueQuestion("TPM Clear?")==True: + tpmclear(pdata) + elif (w=='tpmprovision'): + if continueQuestion("TPM Provision?")==True: + tpmprovision(pdata) + elif (w=='makebetterdescription'): + e['description']=makebetterdescription(pdata) + elif (w=='collecthostinfo'): + e["host"] = collecthostinfo() + elif (w=='collectuefi'): + e["uefi"]={} + e["uefi"]["eventlog"] = collectuefi() + elif (w=='collecttpm2'): + e["tpm2"]={} + e["tpm2"] = pdata["tpm2"] + elif (w=='collectima'): + e["ima"]={} + e["ima"]["asciilog"] = collectima() + elif (w=='processelement'): + i=processelement(pdata,e,cmd) + writeIDtoFile(i) + elif (w=='processevs'): + processevs(pdata,i,cmd,False) + elif (w=='processevs_withrules'): + processevs(pdata,i,cmd,True) + else: + print("Unknown provision work command",w) + + return e + +# +# Question +# + +def continueQuestion(msg): + if safemode==True: + return True + + while True: + a = input("Safety check: "+msg+" (ynq) >") + if a=="y": + return True + elif a=="n": + return False + elif a=="q": + print("Terminating immediately") + quit() + else: + print("valid reponses are y=yes, n=no and q=quit now") + + + +# +# Main +# + +def runjp(): + global safemode + print("Jane Element Configuration") + + parser = argparse.ArgumentParser( + prog="jp", + description="Jane Element Configuator", + epilog="this is the epilog") + parser.add_argument('operation') + parser.add_argument('pfile') + parser.add_argument('-u','--unsafe',action='store_true') + args=parser.parse_args() + + safemode = args.unsafe + print("safe mode is ",safemode) + + if not( args.operation in ["create","update"]): + print("Unknown command, not one of: create, update") + quit() + + f = pathlib.Path(args.pfile) + if not f.is_file(): + print("Provisioning file",args.pfile,"does not exist") + quit() + + if ((not IDfileExists()) and args.operation=="update"): + print("/etc/janelementid file is missing for an update operation") + quit() + + try: + with open(args.pfile,'r') as f: + pdata = yaml.safe_load(f) + except: + print("Error processing",args.pfile) + quit() + + print(args.operation=="create",IDfileExists(), args.operation=="create" and IDfileExists()) + + if (args.operation=="create" and IDfileExists()==True): + print("######################################################") + if continueQuestion("Create mode and element ID file exists?")==False: + print("Terminating safely.") + quit() + + + e = {} + e = processWorklist(pdata,args.operation) + + print("Complete.") + + diff --git a/provisioner/pyvenv.cfg b/provisioner/pyvenv.cfg new file mode 100644 index 0000000..c9f6c01 --- /dev/null +++ b/provisioner/pyvenv.cfg @@ -0,0 +1,5 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.13.5 +executable = /usr/bin/python3.13 +command = /usr/bin/python3 -m venv /home/ian/jane/provisioner diff --git a/provisioner/requirements.txt b/provisioner/requirements.txt new file mode 100644 index 0000000..ed137e6 --- /dev/null +++ b/provisioner/requirements.txt @@ -0,0 +1,6 @@ +certifi==2025.8.3 +charset-normalizer==3.4.3 +idna==3.10 +PyYAML==6.0.2 +requests==2.32.5 +urllib3==2.5.0 diff --git a/rima/Makefile b/rima/Makefile new file mode 100644 index 0000000..08d9fef --- /dev/null +++ b/rima/Makefile @@ -0,0 +1,30 @@ +OS=linux +ARCH=amd64 +BINARY_NAME=rima +PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled + + +build: libs fmt + GOOS=${OS} GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + strip ${BINARY_NAME} + ls -l --color=auto ${BINARY_NAME} + + +fmt: + go fmt ./... + +libs: + go get -u + go mod tidy -v + +vet: + go vet -composites=false ./... + +run: build + ./${BINARY_NAME} + +clean: + go clean + rm ${BINARY_NAME} diff --git a/rima/configuration/configuration.go b/rima/configuration/configuration.go new file mode 100644 index 0000000..7e37091 --- /dev/null +++ b/rima/configuration/configuration.go @@ -0,0 +1,11 @@ +package configuration + +type ConfigurationStruct struct { + JaneURL string + Port string + DBFile string + ScriptDir string + ListenOn string +} + +var ConfigData *ConfigurationStruct diff --git a/rima/database/sdb.go b/rima/database/sdb.go new file mode 100644 index 0000000..c5270aa --- /dev/null +++ b/rima/database/sdb.go @@ -0,0 +1,57 @@ +package database + +import ( + "encoding/csv" + "fmt" + "os" + + "rima/configuration" +) + +type sdbKey struct { + Eid string + Epn string + Pol string +} + +var SDB map[sdbKey]string + +func SetupSDB() { + SDB = make(map[sdbKey]string) + + // Load in DB + fmt.Printf("loading %v\n", configuration.ConfigData.DBFile) + + f, err := os.Open(configuration.ConfigData.DBFile) + if err != nil { + panic(fmt.Sprintf("DB file %v does not exist.\n", configuration.ConfigData.DBFile)) + } + defer f.Close() + + csvReader := csv.NewReader(f) + dbdata, err := csvReader.ReadAll() + if err != nil { + panic(fmt.Sprintf("DB file is corrupt. Error is %v\n", err.Error())) + } + + populateSDB(dbdata) + + fmt.Printf("SBD has %v entries\n", DBSize()) +} + +// Format of DB is ElementItemID, Policy identifier, script name +func populateSDB(data [][]string) { + for j, line := range data { + fmt.Printf(" Entry #%v is %v %v %v\n", j, line[0], line[1], line[2], line[3]) + SDB[sdbKey{line[0], line[1], line[2]}] = line[3] + } +} + +func GetEntry(eid string, epn string, pol string) (string, bool) { + val, ok := SDB[sdbKey{eid, epn, pol}] + return val, ok +} + +func DBSize() int { + return len(SDB) +} diff --git a/rima/go.mod b/rima/go.mod new file mode 100644 index 0000000..9ce807b --- /dev/null +++ b/rima/go.mod @@ -0,0 +1,3 @@ +module rima + +go 1.24.2 diff --git a/rima/processing/call.go b/rima/processing/call.go new file mode 100644 index 0000000..b7b8450 --- /dev/null +++ b/rima/processing/call.go @@ -0,0 +1,28 @@ +package processing + +import ( + "fmt" + "os/exec" + + "rima/configuration" + "rima/database" +) + +func CallScript(url string, eid string, epn string, pol string, msg string) (string, string, error) { + fmt.Printf("Call string %v, %v, %v, %v\n", eid, epn, pol, msg) + + dbe, ok := database.GetEntry(eid, epn, pol) + fmt.Printf(" ---> entry %v, %v\n", dbe, ok) + + scriptlocation := fmt.Sprintf("%v/%v", configuration.ConfigData.ScriptDir, dbe) + fmt.Printf(" ---> script %v\n\n", scriptlocation) + + cmd := exec.Command(scriptlocation, url, eid, epn, pol, msg) + out, err := cmd.Output() + if err != nil { + fmt.Printf("\n\nerror is %v\n", err.Error()) + } + + //instead of alice we should be taking the contents of the last line - which according to convention should just be a sessionid + return "alice", string(out), nil +} diff --git a/rima/restapi/pcall.go b/rima/restapi/pcall.go new file mode 100644 index 0000000..130e417 --- /dev/null +++ b/rima/restapi/pcall.go @@ -0,0 +1,56 @@ +package restapi + +import ( + "encoding/json" + "fmt" + "net/http" + + "rima/configuration" + "rima/processing" +) + +type pcallRequest struct { + EID string `json:"eid"` + EPN string `json:"epn"` + Pol string `json:"pol"` + Msg string `json:"msg"` +} + +type pcallResponse struct { + Sid string `json:"sid"` + Out string `json:"out"` +} + +type pcallErrorResponse struct { + Error string `json:"error"` + Out string `json:"out"` +} + +func PcallHandler(w http.ResponseWriter, r *http.Request) { + var data pcallRequest + + err := json.NewDecoder(r.Body).Decode(&data) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + } + + sid, out, err := processing.CallScript(configuration.ConfigData.JaneURL, data.EID, data.EPN, data.Pol, data.Msg) + + fmt.Printf("sid: %v\nout: %v\n err: %v\n", sid, out, err) + + if err != nil { + eresponse := pcallErrorResponse{Error: err.Error(), Out: out} + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(eresponse); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + response := pcallResponse{Sid: sid, Out: out} + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/rima/restapi/root.go b/rima/restapi/root.go new file mode 100644 index 0000000..27b57e5 --- /dev/null +++ b/rima/restapi/root.go @@ -0,0 +1,10 @@ +package restapi + +import ( + "fmt" + "net/http" +) + +func RootHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, "Welcome - Rima is running") +} diff --git a/rima/restapi/status.go b/rima/restapi/status.go new file mode 100644 index 0000000..cbe84a0 --- /dev/null +++ b/rima/restapi/status.go @@ -0,0 +1,18 @@ +package restapi + +import ( + "encoding/json" + "net/http" + + "rima/configuration" +) + +func StatusHandler(w http.ResponseWriter, r *http.Request) { + response := configuration.ConfigData + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(response); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/rima/rima b/rima/rima new file mode 100755 index 0000000..8bb20a7 Binary files /dev/null and b/rima/rima differ diff --git a/rima/rima.db b/rima/rima.db new file mode 100644 index 0000000..7e16bd1 --- /dev/null +++ b/rima/rima.db @@ -0,0 +1,2 @@ +d1b09fae-c996-4b4c-9678-0724cf15fc8c,a01rest,quick,script1.sh +d1b09fae-c996-4b4c-9678-0724cf15fc8c,a01rest,pain,script2.sh \ No newline at end of file diff --git a/rima/rima.go b/rima/rima.go new file mode 100644 index 0000000..ec9b7b7 --- /dev/null +++ b/rima/rima.go @@ -0,0 +1,45 @@ +package main + +import ( + "flag" + "fmt" + "net/http" + + "rima/configuration" + "rima/database" + "rima/restapi" + "rima/ui" +) + +// Version number +const VERSION string = "v0.1 RIMA" + +// the BUILD value can be set during compilation. +var BUILD string = "not set" + +// Command line flags +var janeURL string +var port string +var dbfile string +var scriptDir string +var listenOn string + +func main() { + flag.StringVar(&janeURL, "jane", "http://127.0.0.1:8520", "Address of Jane's REST API, eg: http://127.0.0.1:8540") + flag.StringVar(&port, "port", "8522", "Port on which Rima runs, defaults to 8522") + flag.StringVar(&dbfile, "db", "./rima.db", "Location of DB file, defaults to ./rima.db") + flag.StringVar(&scriptDir, "scripts", "./rimascripts/", "Location (path to director) of scripts, defaults to ./rimascripts/") + flag.StringVar(&listenOn, "listen", "0.0.0.0", "Which address should Rima listen on, defaults to 0.0.0.0") + + flag.Parse() + configuration.ConfigData = &configuration.ConfigurationStruct{JaneURL: janeURL, Port: port, DBFile: dbfile, ScriptDir: scriptDir, ListenOn: listenOn} + + database.SetupSDB() + ui.WelcomeMessage(VERSION, BUILD) + + http.HandleFunc("/", restapi.RootHandler) + http.HandleFunc("/pcall", restapi.PcallHandler) + http.HandleFunc("/status", restapi.StatusHandler) + + http.ListenAndServe(fmt.Sprintf("%v:%v", listenOn, port), nil) +} diff --git a/rima/rimascripts/script1.sh b/rima/rimascripts/script1.sh new file mode 100755 index 0000000..92551a9 --- /dev/null +++ b/rima/rimascripts/script1.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +# $1 is the URL of the Jane server, eg: http://127.0.0.1:8520 +# $2 is the itemId of the element being requested +# $3 is the specific policy in Rima +# $4 is a message to be included in the session opening + +JANE=$1 +EID=$2 +EPN=$3 +RIMAPOLID=$4 +MSG=$5 + +echo Jane=$1 +echo Eid=$2 +echo Epn=$3 +echo Rimapolid=$4 +echo Msg=$5 + +# Open a session +# Put the message into a form that CURL can understand without too much shell variable expansion insanity + +msgjson=$( jq --null-input --arg message "$MSG" '{"message":$message}' ) +SESSION=$(curl -s -X POST $JANE/session -H "Content-Type: application/json" --data "${msgjson}" | jq -r .itemid) + +# Claims + +INTENT1=std::intent::sys::info + +echo Intent1 is $INTENT1 + +cjson=$( jq --null-input --arg eid "$EID" --arg iid "$INTENT1" --arg sid "$SESSION" '{"eid":$eid,"epn":"a01rest", "pid":$iid, "sid":$sid}' ) +echo cjson $cjson +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" + +echo Claim 1 is $CLAIMID1 + +#CLAIMID2="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data '{"eid":"'$EID'","epn":"'$EPN'", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +#CLAIMID3="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data '{"eid":"'$EID'","epn":"'$EPN'", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" + + +# Close the session + +curl -s -X DELETE $JANE/session/$SESSION > /dev/null + +# Write out the Session ID if any + +echo $SESSION \ No newline at end of file diff --git a/rima/rimascripts/script2.sh b/rima/rimascripts/script2.sh new file mode 100755 index 0000000..cc0436e --- /dev/null +++ b/rima/rimascripts/script2.sh @@ -0,0 +1,407 @@ +#!/bin/sh + +# $1 is the URL of the Jane server, eg: http://127.0.0.1:8520 +# $2 is the itemId of the element being requested +# $3 is the specific policy in Rima +# $4 is a message to be included in the session opening + +JANE=$1 +EID=$2 +RIMAPOLID=$3 +MSG=$4 + +echo Jane=$1 +echo Eid=$2 + +# Open a session +# Put the message into a form that CURL can understand without too much shell variable expansion insanity + +msgjson=$( jq --null-input --arg message "$MSG" '{"message":$message}' ) +SESSION=$(curl -s -X POST $JANE/session -H "Content-Type: application/json" --data "${msgjson}" | jq -r .itemid) + +# Claims + +INTENT1=std::intent::sys::info + +echo Intent1 is $INTENT1 + +cjson=$( jq --null-input --arg eid "$EID" --arg iid "$INTENT1" --arg sid "$SESSION" '{"eid":$eid,"epn":"a01rest", "pid":$iid, "sid":$sid}' ) +echo cjson $cjson + +# We repeat this about 50 times +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 +CLAIMID1="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" +echo Claim 1 is $CLAIMID1 + + +#CLAIMID2="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data '{"eid":"'$EID'","epn":"tarzan", "pid":"'$POLICY2'","sid":"'$SESSION'"}' | jq -r .itemid)" +#CLAIMID3="$(curl -s -X POST $JANE/attest -H "Content-Type: application/json" --data '{"eid":"'$EID'","epn":"tarzan", "pid":"'$POLICY3'","sid":"'$SESSION'"}' | jq -r .itemid)" + + +# Close the session + +curl -s -X DELETE $JANE/session/$SESSION > /dev/null + +# Write out the Session ID if any + +echo $SESSION \ No newline at end of file diff --git a/rima/testcall.sh b/rima/testcall.sh new file mode 100755 index 0000000..ea7f979 --- /dev/null +++ b/rima/testcall.sh @@ -0,0 +1,15 @@ +#/bin/sh -x + +RIMAURL=http://127.0.0.1:8522/pcall +EID=d1b09fae-c996-4b4c-9678-0724cf15fc8c +EPN=a01rest +POL=quick +MSG=Test + + +cjson=$( jq --null-input --arg eid "$EID" --arg epn "$EPN" --arg pol "$POL" --arg msg "$MSG" '{"eid":$eid,"epn":$epn, "pol":$pol, "msg":$msg}' ) +echo cjson $cjson +curl -s -X POST $RIMAURL -H "Content-Type: application/json" --data "${cjson}" + +#CLAIMID1="$(curl -s -X POST $RIMAURL -H "Content-Type: application/json" --data "${cjson}" | jq -r .itemid)" + diff --git a/rima/ui/welcome.go b/rima/ui/welcome.go new file mode 100644 index 0000000..38aba89 --- /dev/null +++ b/rima/ui/welcome.go @@ -0,0 +1,25 @@ +package ui + +import ( + "fmt" + "runtime" + + "rima/configuration" + "rima/database" +) + +// Provides the standard welcome message to stdout. +func WelcomeMessage(VERSION string, BUILD string) { + lensdb := database.DBSize() + + fmt.Printf("\n") + fmt.Printf("+========================================================\n") + fmt.Printf("| RIMA\n") + fmt.Printf("| + %v O/S on %v\n", runtime.GOOS, runtime.GOARCH) + fmt.Printf("| + version %v, build %v\n", VERSION, BUILD) + fmt.Printf("| + Listening on port %v bound to %v\n", configuration.ConfigData.Port, configuration.ConfigData.ListenOn) + fmt.Printf("| + Jane is at %v\n", configuration.ConfigData.JaneURL) + fmt.Printf("| + DB %d entries in %v \n", lensdb, configuration.ConfigData.DBFile) + fmt.Printf("| + Scripts at %v\n", configuration.ConfigData.ScriptDir) + fmt.Printf("+========================================================\n") +} diff --git a/scripts/att.sh b/scripts/att.sh deleted file mode 100755 index 8b4b0bb..0000000 --- a/scripts/att.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -ELEMENT=765e0188-a609-49c0-bf61-3825849413cd -POLICY=ba64f197-0eb3-4f3f-a74d-a9a8e0a3f17d - -EN="$(curl -s -X GET http://127.0.0.1:8520/element/$ELEMENT | jq -r .name)" -PN="$(curl -s -X GET http://127.0.0.1:8520/policy/$POLICY | jq -r .name)" - - -echo Applying $PN to $EN - - -#open session -SESSION="$(curl -s -X POST http://127.0.0.1:8520/session -H "Content-Type: application/json" --data '{"message":"test from curl"}' | jq -r .itemid)" - -#attest element -CLAIMID="$(curl -s -X POST http://127.0.0.1:8520/attest -H "Content-Type: application/json" --data '{"eid":"'$ELEMENT'","pid":"'$POLICY'","sid":"'$SESSION'"}' | jq -r .itemid)" - -#close session -curl -s -X DELETE http://127.0.0.1:8520/session/$SESSION > /dev/null - -#Print stuff -echo Session was $SESSION with claim $CLAIMID -curl -s -X GET http://127.0.0.1:8520/claim/$CLAIMID | jq .body.sha256 \ No newline at end of file diff --git a/ta10/go.mod b/ta10/go.mod deleted file mode 100644 index 9fec6c1..0000000 --- a/ta10/go.mod +++ /dev/null @@ -1,24 +0,0 @@ -module ta10 - -go 1.20 - -require ( - github.com/google/go-tpm v0.9.0 - github.com/google/uuid v1.5.0 - github.com/labstack/echo/v4 v4.11.4 -) - -require ( - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/labstack/gommon v0.4.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - golang.org/x/crypto v0.18.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect - -) diff --git a/ta10/go.sum b/ta10/go.sum deleted file mode 100644 index 6e71eff..0000000 --- a/ta10/go.sum +++ /dev/null @@ -1,35 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= -github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= -github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= -github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= -github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/ta10/sys/endpoints.go b/ta10/sys/endpoints.go deleted file mode 100644 index 7876b10..0000000 --- a/ta10/sys/endpoints.go +++ /dev/null @@ -1,47 +0,0 @@ -package sys - -import( - "net/http" - "runtime" - "os" - "fmt" - - "ta10/common" - - "github.com/labstack/echo/v4" -) - -type sysinfoReturn struct { - OS string `json:"os"` - Arch string `json:"arch"` - NCPU int `json:"ncpu"` - Hostname string `json:"hostname"` - Unsafe bool `json:"unsafe"` - Pid int `json:"pid"` - Ppid int `json:"ppid"` - - -} - -func getHostname() string { - hostname := "?" - - h,err := os.Hostname() - if (err==nil) { - hostname=h - } - - return hostname -} - - -func Sysinfo(c echo.Context) error { - fmt.Println("sysinfo called") - - ncpus := runtime.NumCPU() - - - s := sysinfoReturn{ runtime.GOOS, runtime.GOARCH, ncpus, getHostname(), utilities.IsUnsafe(), os.Getpid(), os.Getppid() } - - return c.JSON(http.StatusOK, s) -} diff --git a/ta10/ta10.go b/ta10/ta10.go deleted file mode 100644 index 78d04b3..0000000 --- a/ta10/ta10.go +++ /dev/null @@ -1,169 +0,0 @@ -// Attestation Engine A10 -// Golang version v0.1 -// The main package starts the various interfaces: REST, MQTT and links to the database system -package main - -import ( - "fmt" - "runtime" - "flag" - - "ta10/common" - - "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" - - "ta10/sys" - "ta10/uefi" - "ta10/ima" - "ta10/tpm2" -) - -// Version number -const VERSION string = "v0.1" -var BUILD string = "not set" -var RUNSESSION string = utilities.MakeID() - -const PREFIX="" - - - - - - -// Provides the standard welcome message to stdout. -func welcomeMessage(unsafe bool) { - fmt.Printf("\n") - fmt.Printf("+========================================================================================\n") - fmt.Printf("| TA10 version - Starting\n",) - fmt.Printf("| + %v O/S on %v\n",runtime.GOOS,runtime.GOARCH) - fmt.Printf("| + version %v, build %v\n",VERSION,BUILD) - fmt.Printf("| + session identifier is %v\n",RUNSESSION) - fmt.Printf("| + unsafe mode? %v\n",unsafe) - fmt.Printf("+========================================================================================\n\n") -} - -func exitMessage() { - fmt.Printf("\n") - fmt.Printf("+========================================================================================\n") - fmt.Printf("| TA10 version - Exiting\n",) - fmt.Printf("| + session identifier was %v\n",RUNSESSION) - fmt.Printf("+========================================================================================\n\n") -} - -func checkUnsafeMode(unsafe bool) { - if unsafe==true { - utilities.SetUnsafeMode() - - fmt.Printf("\n") - fmt.Printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") - fmt.Printf("TA10 is running in UNSAFE file access mode. Unsafe is set to %v\n",utilities.IsUnsafe()) - fmt.Printf("Requests for log files, eg: UEFI, IMA, that supply a non default location will happily read that file\n") - fmt.Printf("This is a HUGE security issue. YOU HAVE BEEN WARNED\n") - fmt.Printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") - - } -} - - -// This function initialises the system by calling the configuration system to read the configuration -func initialise() { - flag.Parse() -} - - -// These configure the rest API - - -func startRESTInterface(sys,tpm,uefi,ima,txt bool, p *string ) { - router := echo.New() - router.HideBanner = true - - //not necessary, but I will keep this here because this is now my example of how to use middlewares - //in echo, plus the import declaration above - // - // Of the two below, the gzip is the only useful one. The BodyDump was used for debugging - // - //router.Use(middleware.BodyDump(func(c echo.Context,reqBody,resBody []byte) {} )) - router.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Level: 5,})) - - if sys == true { - setupSYSendpoints(router) - } - if uefi == true { - setupUEFIendpoints(router) - } - if ima == true { - setupIMAendpoints(router) - } - - if tpm == true { - setupTPM2endpoints(router) - } - if ima == true { - setupIMAendpoints(router) - } -/* if txt == true { - setupTXTendpoints(router) - } -*/ - - //get configuration data - port := ":"+ *p - //crt := configuration.ConfigData.Rest.Crt - //key:= configuration.ConfigData.Rest.Key - usehttp := true - - //start the server - if usehttp == true{ - router.Logger.Fatal(router.Start(string(port))) - - } else { - //router.Logger.Fatal(router.StartTLS(port,crt,key)) - } -} - - -func setupSYSendpoints(router *echo.Echo) { - router.POST(PREFIX+"/sys/info", sys.Sysinfo) -} - -func setupUEFIendpoints(router *echo.Echo) { - router.POST(PREFIX+"/uefi/eventlog", uefi.Eventlog) -} - -func setupIMAendpoints(router *echo.Echo) { - router.POST(PREFIX+"/ima/asciilog", ima.ASCIILog) -} - -func setupTPM2endpoints(router *echo.Echo) { - router.POST(PREFIX+"/tpm2/pcrs", tpm2.PCRs) - router.POST(PREFIX+"/tpm2/quote", tpm2.Quote) -} - - - - - -// This starts everything...here we "go" :-) -func main() { - flagSYS := flag.Bool("sys", true, "Expose the sys attestation API") - flagTPM := flag.Bool("tpm", true, "Expose the tpm attesation API") - flagUEFI := flag.Bool("uefi", true, "Expose the uefi attestation API") - flagIMA := flag.Bool("ima", true, "Expose the ima attestation API") - flagTXT := flag.Bool("txt", true, "Expose the txt attestation API") - - flagUNSAFEFILEACCESS := flag.Bool("unsafe", false, "Allow caller to request ANY file instead of the default UEFI and IMA locations. THIS IS UNSAFE!") - - flagPort := flag.String("port", "8530", "Run the TA on the given port. Defaults to 8530") - - flag.Parse() - - fmt.Printf("\nsys %v, port %v , unsafe %v\n", flagSYS, flagPort, flagUNSAFEFILEACCESS) - - welcomeMessage(*flagUNSAFEFILEACCESS) - checkUnsafeMode(*flagUNSAFEFILEACCESS) - - startRESTInterface(*flagSYS, *flagTPM, *flagUEFI, *flagIMA, *flagTXT, flagPort ) - exitMessage() -} diff --git a/ta10/tpm2/endpointstpm2.go b/ta10/tpm2/endpointstpm2.go deleted file mode 100644 index 9b575b5..0000000 --- a/ta10/tpm2/endpointstpm2.go +++ /dev/null @@ -1,217 +0,0 @@ -//go:build !windows - -package tpm2 - -import ( - "encoding/base64" - "encoding/hex" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/labstack/echo/v4" - - // this needs to be updated - "github.com/google/go-tpm/legacy/tpm2" - "github.com/google/go-tpm/tpmutil" -) - -type tpm2taErrorReturn struct { - TPM2taError string `json:"tpm2taerror"` -} - -type pcrValue map[int]string - -type quoteReturn struct { - Quote []byte `json:"quote"` - Signature []byte `json:"signature"` -} - -var bankNames = map[tpm2.Algorithm]string{ - tpm2.AlgSHA1: "sha1", - tpm2.AlgSHA256: "sha256", - tpm2.AlgSHA384: "sha384", - tpm2.AlgSHA512: "sha512", -} - -var bankValues = map[string]tpm2.Algorithm{ - "sha1": tpm2.AlgSHA1, - "sha256": tpm2.AlgSHA256, - "sha384": tpm2.AlgSHA384, - "sha512": tpm2.AlgSHA512, -} - -var pcrbanks = []tpm2.Algorithm{tpm2.AlgSHA1, tpm2.AlgSHA256, tpm2.AlgSHA384, tpm2.AlgSHA512} - -// PCRs needs to be supplied the following parameters in the POST body -// -// tpm string ... which TPM to use -func PCRs(c echo.Context) error { - fmt.Println("tpm2 pcrs called") - - // Obtain the parameters - ps := new(map[string]interface{}) - - if err := c.Bind(&ps); err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Could not decode parameters %w", err.Error())} - return c.JSON(http.StatusUnprocessableEntity, rtn) - } - - params := *ps - - // Here we parse the tpm2 device - // We have a default of /dev/tpm0 - tpm2device := params["tpm2/device"].(string) - fmt.Printf("TPM2Device is %v \n",tpm2device) - - rwc, err := OpenTPM(tpm2device) - if err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("no TPM %w", err.Error())} - fmt.Printf("no TPM ERROR is %v \n",err.Error() ) - - return c.JSON(http.StatusInternalServerError, rtn) - } - defer rwc.Close() - - fmt.Printf("TPM readwriteio object is %v\n",rwc) - - banks := make(map[string]pcrValue) - - for _, b := range pcrbanks { - pcrvs := make(map[int]string) - - for i := 0; i <= 23; i++ { - fmt.Printf("Reading back %v, pcr %v --> ",b,i) - pcrv, pcre := tpm2.ReadPCR(rwc, i, b) - fmt.Printf(" hex %v err %w\n",pcrv,pcre) - if pcre == nil { - pcrvs[i] = hex.EncodeToString(pcrv) - } - } - banks[bankNames[b]] = pcrvs - } - return c.JSON(http.StatusOK, banks) -} - -// Quote needs to be supplied the following parameters in the POST body -// -// pcrSelection []int8 -// akhandle string (converts to hex) where the sigining key is -// tpm string ... which TPM to use -// nonce []int8 the nonce -func Quote(c echo.Context) error { - fmt.Println("tpm2 quote called...") - - // Obtain the parameters - ps := new(map[string]interface{}) - - if err := c.Bind(&ps); err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Could not decode parameters %v", err.Error())} - return c.JSON(http.StatusUnprocessableEntity, rtn) - } - - fmt.Println("got the parameters...") - - params := *ps - - // Here we parse the pcrSelection to obtain the []int structure for the pcrselections - s := strings.Split(params["pcrSelection"].(string), ",") - pcrsel := make([]int, len(s), len(s)) - for i, r := range s { - v64, err := strconv.ParseUint(r, 10, 8) - - if err != nil { - pcrsel[i] = 0 - } else { - pcrsel[i] = int(v64) - } - } - - // Here we parse the bank - b := params["bank"].(string) - pcrbank := bankValues[b] - - // Here we parse the nonce - // If none then one will be generated - nonce := params["tpm2/nonce"].(string) - - nonceBytes, err := base64.StdEncoding.DecodeString(nonce) - if err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Could not base64 decode nonce", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - - // Here we parse the akhandle - // This is a bit ugly but...that's the way go does things - // Strip the 0x, parse it as a Uint in base 16 with size 32 - returns a unit64, convert to a uint32 and then create the TPM handle - akh := strings.Replace(params["tpm2/akhandle"].(string), "0x", "", -1) - h, err := strconv.ParseUint(akh, 16, 32) - if err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Unable to parse AK handle %w", err.Error())} - return c.JSON(http.StatusUnprocessableEntity, rtn) - } - h32 := uint32(h) // this is safe because we only create a 32bit unsigned value above. - handle := tpmutil.Handle(h32) - - // Here we parse the tpm2 device - // We have a default of /dev/tpm0 - tpm2device := params["tpm2/device"].(string) - - // Here we commuicate with the TPM - // Default if /dev/tpm0 - - fmt.Println("Opening device") - - rwc, err := OpenTPM(tpm2device) - if err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("no TPM %w", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - defer rwc.Close() - - fmt.Println("Quoting") - - // Here we obtain the Quote - att, sig, err := tpm2.Quote( - rwc, - handle, - "", - "", - nonceBytes, - tpm2.PCRSelection{pcrbank, pcrsel}, - tpm2.AlgNull) - - fmt.Println("Got the quote...processing errors %v", err) - - if err != nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Error obtaining quote %v", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - if sig == nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("No signature in quote %v", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - if att == nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("No quote received %v", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - - fmt.Sprintf("Decoding attestation data") - - attestationdata, err := tpm2.DecodeAttestationData(att) - - if attestationdata == nil { - rtn := tpm2taErrorReturn{fmt.Sprintf("Error decoding attestation data %v", err.Error())} - return c.JSON(http.StatusInternalServerError, rtn) - } - - fmt.Println("Att and Sig are %v and %v", att, sig) - - sigBytes, _ := sig.Encode() - qr := quoteReturn{att, sigBytes} - - fmt.Printf("qr is %v", qr) - - return c.JSON(http.StatusOK, qr) -} diff --git a/ta10/tpm2/opentpm_unix.go b/ta10/tpm2/opentpm_unix.go deleted file mode 100644 index 62ccfa3..0000000 --- a/ta10/tpm2/opentpm_unix.go +++ /dev/null @@ -1,27 +0,0 @@ -//go:build !windows - -package tpm2 - -import( - "fmt" - "io" - "net" - "slices" - - "github.com/google/go-tpm/legacy/tpm2" -) - -var TPMDEVICES = []string{ "/dev/tpm0", "/dev/tpmrm0", "/dev/tpm1", "/dev/tpmrm1", } - -func OpenTPM(path string) (io.ReadWriteCloser,error) { - fmt.Printf("TPM Device path >>> %v <<< passed as parameter. This is a Unix build: ",path) - - // Check if the path is a known device, else treat it as a unix domain socket - if slices.Contains(TPMDEVICES,path) { - fmt.Printf("Treating it as a device\n") - return tpm2.OpenTPM(path) - } else { - fmt.Printf("Treating it as a TCP Unix domain socket\n") - return net.Dial("tcp",path) - } -} diff --git a/ta10/uefi/endpoints.go b/ta10/uefi/endpoints.go deleted file mode 100644 index 42225d2..0000000 --- a/ta10/uefi/endpoints.go +++ /dev/null @@ -1,57 +0,0 @@ -package uefi - -import ( - "encoding/base64" - "fmt" - "io/ioutil" - "net/http" - - utilities "ta10/common" - - "github.com/labstack/echo/v4" -) - -const UEFIEVENTLOGLOCATION string = "/sys/kernel/security/tpm0/binary_bios_measurements" - -type returnEventLog struct { - EventLog string `json:"eventlog"` - Encoding string `json:"encoded"` - UnEncodedLength int `json:"unencodedlength"` - EncodedLength int `json:"encodedlength"` -} - -func GetEventLogLocation(loc string) string { - fmt.Printf("UEFI Log requested from %v, unsafe mode is %v, giving: ", loc, utilities.IsUnsafe()) - - if utilities.IsUnsafe() == true { - fmt.Printf("%v\n", loc) - return loc - } else { - fmt.Printf("%v\n", UEFIEVENTLOGLOCATION) - return UEFIEVENTLOGLOCATION - } -} - -func Eventlog(c echo.Context) error { - fmt.Println("eventlog called") - - var postbody map[string]interface{} - var rtnbody = make(map[string]interface{}) - - if err := c.Bind(&postbody); err != nil { - rtnbody["postbody"] = err.Error() - return c.JSON(http.StatusUnprocessableEntity, rtnbody) - } - - u := GetEventLogLocation(fmt.Sprintf("%v", postbody["uefi/eventlog"])) - - fcontent, err := ioutil.ReadFile(u) - if err != nil { - rtnbody["file err"] = err.Error() - return c.JSON(http.StatusInternalServerError, rtnbody) - } - scontent := base64.StdEncoding.EncodeToString(fcontent) - - rtn := returnEventLog{scontent, "base64", len(fcontent), len(scontent)} - return c.JSON(http.StatusOK, rtn) -} diff --git a/tarzan/Makefile b/tarzan/Makefile new file mode 100644 index 0000000..527d5de --- /dev/null +++ b/tarzan/Makefile @@ -0,0 +1,31 @@ +OS=linux +ARCH=amd64 +BINARY_NAME=tarzan +PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled + + +build: libs fmt + GOOS=${OS} GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + strip ${BINARY_NAME} + ls -l --color=auto ${BINARY_NAME} + + + +fmt: + go fmt ./... + +libs: + go get -u + go mod tidy -v + +vet: + go vet -composites=false ./... + +run: build + ./${BINARY_NAME} + +clean: + go clean + rm ${BINARY_NAME} diff --git a/tarzan/Makefile.arm6 b/tarzan/Makefile.arm6 new file mode 100644 index 0000000..7d4e41e --- /dev/null +++ b/tarzan/Makefile.arm6 @@ -0,0 +1,30 @@ +OS=linux +ARCH=arm +ARMCPU=6 +BINARY_NAME=tarzan_arm6 +#PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled + + +build: libs fmt + GOOS=${OS} GOARM=6 GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + + + +fmt: + go fmt ./... + +libs: + go get -u + go mod tidy -v + +vet: + go vet -composites=false ./... + +run: build + ./${BINARY_NAME} + +clean: + go clean + rm ${BINARY_NAME} diff --git a/tarzan/Makefile.arm64 b/tarzan/Makefile.arm64 new file mode 100644 index 0000000..65d1a19 --- /dev/null +++ b/tarzan/Makefile.arm64 @@ -0,0 +1,29 @@ +OS=linux +ARCH=arm64 +BINARY_NAME=tarzan_arm +#PIE_ON=-buildmode=pie +BUILD_DATE=`date` +VERSION=locally_compiled + + +build: libs fmt + GOOS=${OS} GOARCH=${ARCH} /usr/local/go/bin/go build -ldflags="-X 'main.BUILD=${BUILD_DATE} main.VERSION=${VERSION}'" ${PIE_ON} -o ${BINARY_NAME} + + + +fmt: + go fmt ./... + +libs: + go get -u + go mod tidy -v + +vet: + go vet -composites=false ./... + +run: build + ./${BINARY_NAME} + +clean: + go clean + rm ${BINARY_NAME} diff --git a/ta10/common/identifiers.go b/tarzan/common/identifiers.go similarity index 64% rename from ta10/common/identifiers.go rename to tarzan/common/identifiers.go index 8a40edd..8894043 100644 --- a/ta10/common/identifiers.go +++ b/tarzan/common/identifiers.go @@ -1,10 +1,9 @@ package utilities -import( - "github.com/google/uuid" +import ( + "github.com/google/uuid" ) - func MakeID() string { return uuid.New().String() } diff --git a/tarzan/common/runtimeidentifier.go b/tarzan/common/runtimeidentifier.go new file mode 100644 index 0000000..3f96f4c --- /dev/null +++ b/tarzan/common/runtimeidentifier.go @@ -0,0 +1,3 @@ +package utilities + +var RUNSESSION string diff --git a/ta10/common/unsafemode.go b/tarzan/common/unsafemode.go similarity index 98% rename from ta10/common/unsafemode.go rename to tarzan/common/unsafemode.go index 23bc129..ad5fe46 100644 --- a/ta10/common/unsafemode.go +++ b/tarzan/common/unsafemode.go @@ -1,6 +1,5 @@ package utilities - var unsafemode bool = false func SetUnsafeMode() { @@ -9,4 +8,4 @@ func SetUnsafeMode() { func IsUnsafe() bool { return unsafemode -} \ No newline at end of file +} diff --git a/tarzan/go.mod b/tarzan/go.mod new file mode 100644 index 0000000..50783d1 --- /dev/null +++ b/tarzan/go.mod @@ -0,0 +1,27 @@ +module ta10 + +go 1.24.0 + +require ( + github.com/0x5a17ed/itkit v0.7.0 + github.com/0x5a17ed/uefi v0.7.0 + github.com/google/go-tpm v0.9.6 + github.com/google/uuid v1.6.0 + github.com/labstack/echo/v4 v4.13.4 +) + +require ( + github.com/labstack/gommon v0.4.2 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/crypto v0.43.0 // indirect + golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.14.0 // indirect +) diff --git a/tarzan/go.sum b/tarzan/go.sum new file mode 100644 index 0000000..4dc80e3 --- /dev/null +++ b/tarzan/go.sum @@ -0,0 +1,51 @@ +github.com/0x5a17ed/itkit v0.7.0 h1:MmXKtpNtlavis7IJvQtHeCmBFrQpUVFCovetv4FO9dM= +github.com/0x5a17ed/itkit v0.7.0/go.mod h1:v22t2Uc3bKewFBwLkY2U1KM7Us8iiEWw3qGqJFU76rI= +github.com/0x5a17ed/uefi v0.7.0 h1:yfHBebSj4AaKdbLe8PESGsXDcLi7OnM2yGVlVyMLZ/E= +github.com/0x5a17ed/uefi v0.7.0/go.mod h1:eCuHcWWaNlbhSq2w2YXwWxbyq+esp7rNnADxV+tlafY= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-tpm v0.9.6 h1:Ku42PT4LmjDu1H5C5ISWLlpI1mj+Zq7sPGKoRw2XROA= +github.com/google/go-tpm v0.9.6/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba h1:qJEJcuLzH5KDR0gKc0zcktin6KSAwL7+jWKBYceddTc= +github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:EFYHy8/1y2KfgTAsx7Luu7NGhoxtuVHnNo8jE7FikKc= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA= +github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA= +golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/ta10/ima/endpoints.go b/tarzan/ima/endpoints.go similarity index 100% rename from ta10/ima/endpoints.go rename to tarzan/ima/endpoints.go diff --git a/tarzan/sys/endpoints.go b/tarzan/sys/endpoints.go new file mode 100644 index 0000000..977ac8c --- /dev/null +++ b/tarzan/sys/endpoints.go @@ -0,0 +1,57 @@ +package sys + +import ( + "fmt" + "net/http" + "os" + "runtime" + "strings" + + "ta10/common" + + "github.com/labstack/echo/v4" +) + +type sysinfoReturn struct { + OS string `json:"os"` + Arch string `json:"arch"` + NCPU int `json:"ncpu"` + Hostname string `json:"hostname"` + Unsafe bool `json:"unsafe"` + Pid int `json:"pid"` + Ppid int `json:"ppid"` + Uid int `json:"uid"` + SessionID string `json:"sessionid"` + MachineID string `json:"machineid"` +} + +func getHostname() string { + hostname := "?" + + h, err := os.Hostname() + if err == nil { + hostname = h + } + + return hostname +} + +func Sysinfo(c echo.Context) error { + var machineid string + + fmt.Println("sysinfo called") + + machineidbytes, err := os.ReadFile("/etc/machine-id") + if err != nil { + machineid = "" + } else { + mb := string(machineidbytes) + machineid = strings.Trim(fmt.Sprintf("%v", mb), " \t\n") + fmt.Printf("Machine id: %v %v", len(machineid), machineid) + } + + ncpus := runtime.NumCPU() + s := sysinfoReturn{runtime.GOOS, runtime.GOARCH, ncpus, getHostname(), utilities.IsUnsafe(), os.Getpid(), os.Getppid(), os.Getuid(), utilities.RUNSESSION, machineid} + + return c.JSON(http.StatusOK, s) +} diff --git a/tarzan/tarzan.go b/tarzan/tarzan.go new file mode 100644 index 0000000..7237f50 --- /dev/null +++ b/tarzan/tarzan.go @@ -0,0 +1,167 @@ +// The main package starts the various interfaces: REST, MQTT and links to the database system +package main + +import ( + "flag" + "fmt" + "runtime" + + "ta10/common" + + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + + "ta10/ima" + "ta10/sys" + "ta10/tpm2" + "ta10/uefi" +) + +// Version number +const VERSION string = "v0.2" + +var BUILD string = "not set" + +const PREFIX = "" + +// Provides the standard welcome message to stdout. +func welcomeMessage(unsafe bool) { + fmt.Printf("\n") + fmt.Printf("+========================================================\n") + fmt.Printf("| Tarzan\n") + fmt.Printf("| + %v O/S on %v\n", runtime.GOOS, runtime.GOARCH) + fmt.Printf("| + version %v, build %v\n", VERSION, BUILD) + fmt.Printf("| + session identifier is %v\n", utilities.RUNSESSION) + fmt.Printf("| + unsafe mode? %v\n", unsafe) + fmt.Printf("+========================================================\n") +} + +func exitMessage() { + fmt.Printf("\n") + fmt.Printf("+========================================================================================\n") + fmt.Printf("| Tarzan\n") + fmt.Printf("| + session identifier was %v\n", utilities.RUNSESSION) + fmt.Printf("| Hwyl fawr!\n") + fmt.Printf("+========================================================================================\n\n") +} + +func checkUnsafeMode(unsafe bool) { + if unsafe == true { + utilities.SetUnsafeMode() + + fmt.Printf("\n") + fmt.Printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + fmt.Printf("TA10 is running in UNSAFE file access mode. Unsafe is set to %v\n", utilities.IsUnsafe()) + fmt.Printf("Requests for log files, eg: UEFI, IMA, that supply a non default location will happily read that file\n") + fmt.Printf("This is a HUGE security issue. YOU HAVE BEEN WARNED\n") + fmt.Printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") + + } +} + +// These configure the rest API + +func startRESTInterface(sys, tpm2, uefi, ima, txt bool, p *string) { + router := echo.New() + router.HideBanner = true + + //not necessary, but I will keep this here because this is now my example of how to use middlewares + //in echo, plus the import declaration above + // + // Of the two below, the gzip is the only useful one. The BodyDump was used for debugging + // + //router.Use(middleware.BodyDump(func(c echo.Context,reqBody,resBody []byte) {} )) + router.Use(middleware.GzipWithConfig(middleware.GzipConfig{Level: 5})) + + if sys == true { + fmt.Println(" +-- Sys attestation API enabled") + setupSYSendpoints(router) + } + if uefi == true { + fmt.Println(" +-- UEFI attestation API enabled") + setupUEFIendpoints(router) + } + if ima == true { + fmt.Println(" +-- IMA attestation API enabled") + setupIMAendpoints(router) + } + + if tpm2 == true { + fmt.Println(" +-- TPM2 attestation API enabled") + setupTPM2endpoints(router) + } + + /* if txt == true { + fmt.println(" +-- TXT attestation API enabled") + setupTXTendpoints(router) + } + */ + + if sys == false && uefi == false && ima == false && tpm2 == false && txt == false { + fmt.Println(" +-- WARNING: tarzan isn't listening to anyone and won't respond") + } + + //get configuration data + port := ":" + *p + //crt := configuration.ConfigData.Rest.Crt + //key:= configuration.ConfigData.Rest.Key + usehttp := true + + //start the server + if usehttp == true { + fmt.Printf(" +-- HTTP interface on port %v enabled\n", port) + router.Logger.Fatal(router.Start(string(port))) + + } else { + fmt.Printf(" +-- HTTPS interface on port %v enabled\n", port) + //router.Logger.Fatal(router.StartTLS(port,crt,key)) + } +} + +func setupSYSendpoints(router *echo.Echo) { + router.POST(PREFIX+"/sys/info", sys.Sysinfo) +} + +func setupUEFIendpoints(router *echo.Echo) { + router.POST(PREFIX+"/uefi/eventlog", uefi.Eventlog) + router.POST(PREFIX+"/uefi/efivars", uefi.Efivars) + router.POST(PREFIX+"/uefi/bootconfig", uefi.BootConfig) +} + +func setupIMAendpoints(router *echo.Echo) { + router.POST(PREFIX+"/ima/asciilog", ima.ASCIILog) +} + +func setupTPM2endpoints(router *echo.Echo) { + router.POST(PREFIX+"/tpm2/newpcrs", tpm2.NewPCRs) + router.POST(PREFIX+"/tpm2/pcrs", tpm2.NewPCRs) + + router.POST(PREFIX+"/tpm2/newquote", tpm2.NewQuote) + router.POST(PREFIX+"/tpm2/quote", tpm2.NewQuote) + + //router.POST(PREFIX+"/tpm2/pcrs", tpm2.PCRs) + //router.POST(PREFIX+"/tpm2/quote", tpm2.Quote) +} + +// This starts everything...here we "go" :-) +func main() { + utilities.RUNSESSION = utilities.MakeID() + + flagSYS := flag.Bool("sys", false, "Expose the sys attestation API") + flagTPM2 := flag.Bool("tpm2", false, "Expose the tpm2 attesation API") + flagUEFI := flag.Bool("uefi", false, "Expose the uefi attestation API") + flagIMA := flag.Bool("ima", false, "Expose the ima attestation API") + flagTXT := flag.Bool("txt", false, "Expose the txt attestation API") + + flagUNSAFEFILEACCESS := flag.Bool("unsafe", false, "Allow caller to request ANY file instead of the default UEFI and IMA locations. THIS IS UNSAFE!") + + flagPort := flag.String("port", "8530", "Run the TA on the given port. Defaults to 8530") + + flag.Parse() + + welcomeMessage(*flagUNSAFEFILEACCESS) + checkUnsafeMode(*flagUNSAFEFILEACCESS) + + startRESTInterface(*flagSYS, *flagTPM2, *flagUEFI, *flagIMA, *flagTXT, flagPort) + exitMessage() +} diff --git a/tarzan/tpm2/commontypes.go b/tarzan/tpm2/commontypes.go new file mode 100644 index 0000000..15e7927 --- /dev/null +++ b/tarzan/tpm2/commontypes.go @@ -0,0 +1,56 @@ +package tpm2 + +import ( + "github.com/google/go-tpm/tpm2" + _ "github.com/google/go-tpm/tpm2/transport" + _ "github.com/google/go-tpm/tpm2/transport/linuxtpm" +) + +type tpm2taErrorReturn struct { + TPM2taError string `json:"tpm2taerror"` +} + +type clockInfo struct { + Clock string `json:"clock"` + ResetCount string `json:"resetcount"` + RestartCount string `json:"restartcount"` + Safe string `json:"safe"` +} + +type attested struct { + PCRSelect string `json:"pcrselect"` + PCRDigest string `json:"pcrdigest"` +} + +type quoteStructure struct { + Magic string `json:"magic"` + Type string `json:"type"` + QualifiedSigner string `json:"qualifiedsigner"` + ExtraData string `json:"extradata"` + ClockInfo clockInfo `json:"clockinfo"` + FirmwareVersion string `json:"firmwareVersion"` + Attested attested `json:"attested"` +} + +type tpm2quoteReturn struct { + Quote quoteStructure `json:"quote"` + Signature interface{} `json:"signature"` +} + +var npcrbanks = []tpm2.TPMIAlgHash{tpm2.TPMAlgSHA1, tpm2.TPMAlgSHA256, tpm2.TPMAlgSHA384, tpm2.TPMAlgSHA512} + +type pcrValue map[int]string + +var bankNames = map[tpm2.TPMAlgID]string{ + tpm2.TPMAlgSHA1: "sha1", + tpm2.TPMAlgSHA256: "sha256", + tpm2.TPMAlgSHA384: "sha384", + tpm2.TPMAlgSHA512: "sha512", +} + +var bankValues = map[string]tpm2.TPMAlgID{ + "sha1": tpm2.TPMAlgSHA1, + "sha256": tpm2.TPMAlgSHA256, + "sha384": tpm2.TPMAlgSHA384, + "sha512": tpm2.TPMAlgSHA512, +} diff --git a/tarzan/tpm2/opentpm_unix.go b/tarzan/tpm2/opentpm_unix.go new file mode 100644 index 0000000..be32411 --- /dev/null +++ b/tarzan/tpm2/opentpm_unix.go @@ -0,0 +1,26 @@ +//go:build !windows + +package tpm2 + +import ( + "fmt" + "slices" + + "github.com/google/go-tpm/tpm2/transport" + "github.com/google/go-tpm/tpm2/transport/linuxtpm" +) + +var TPMDEVICES = []string{"/dev/tpm0", "/dev/tpmrm0", "/dev/tpm1", "/dev/tpmrm1"} + +func OpenTPM(dev string) (transport.TPMCloser, error) { + fmt.Printf("TPM Device >>> %v <<< passed as parameter. This is a Unix build: ", dev) + + // Check if the path is a known device, else treat it as a unix domain socket + if slices.Contains(TPMDEVICES, dev) { + fmt.Printf("Treating it as a device\n") + return linuxtpm.Open(dev) + } else { + fmt.Printf("Treating it as a TCP Unix domain socket\n") + return linuxtpm.Open(dev) + } +} diff --git a/ta10/tpm2/opentpm_windows.go b/tarzan/tpm2/opentpm_windows.go similarity index 64% rename from ta10/tpm2/opentpm_windows.go rename to tarzan/tpm2/opentpm_windows.go index cb2dae3..8d353b9 100644 --- a/ta10/tpm2/opentpm_windows.go +++ b/tarzan/tpm2/opentpm_windows.go @@ -2,16 +2,15 @@ package tpm2 -import( +import ( "fmt" - "io" "github.com/google/go-tpm/legacy/tpm2" + "io" ) - -func OpenTPM(path string) (io.ReadWriteCloser,error) { +func OpenTPM(path string) (io.ReadWriteCloser, error) { fmt.Sprintf("TPM Device path >>> %v <<< passed as parameter. This is a Windows build and will be ignored.") - rwc,err :=tpm2.OpenTPM() + rwc, err := tpm2.OpenTPM() - return rwc,err + return rwc, err } diff --git a/tarzan/tpm2/pcrread.go b/tarzan/tpm2/pcrread.go new file mode 100644 index 0000000..e07a151 --- /dev/null +++ b/tarzan/tpm2/pcrread.go @@ -0,0 +1,120 @@ +//go:build !windows + +package tpm2 + +import ( + _ "encoding/base64" + _ "encoding/hex" + "fmt" + "net/http" + "reflect" + _ "strconv" + _ "strings" + + "github.com/labstack/echo/v4" + + "github.com/google/go-tpm/tpm2" +) + +func NewPCRs(c echo.Context) error { + + // Honestly this code is freaking awful + // gotpm PCRRead only accepts 8 PCR values at a time, but we want them all which requires + // multiple calls...so we go through each possible bank, one at a time and take one PCR + // at a time and dump them all into a struct (banks)...ugly, it works, but awful + // Oh, and if the PCRs get modified during the call of this function, then the results + // might be inconsistent, but then again PCRs in this form aren't signed so good luck + + //results := []tpm2.PCRReadResponse{} + banks := make(map[string]pcrValue) + + fmt.Println("NEW tpm2 pcrs called") + + // Obtain the parameters + ps := new(map[string]interface{}) + + if err := c.Bind(&ps); err != nil { + fmt.Printf("NewPCRs BIND err %v\n", err.Error()) + rtn := tpm2taErrorReturn{fmt.Sprintf("Could not decode parameters %v", err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + + params := *ps + fmt.Printf("%v\n", params) + + // Here we parse the tpm2 device + // We have a default of /dev/tpm0 + tpm2device := params["tpm2/device"].(string) + + tpm, err := OpenTPM(tpm2device) + if err != nil { + rtn := tpm2taErrorReturn{fmt.Sprintf("Could not open TPM during PCRRead function with error %v", err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + defer func() { + if err := tpm.Close(); err != nil { + fmt.Printf("\ncan't close TPM %q: %v", tpm2device, err) + } + }() + + for _, b := range npcrbanks { + pcrvs := make(map[int]string) + for i := 0; i <= 23; i++ { + //fmt.Printf("Reading back %v, pcr %v -->\n", b, i) + + s2 := tpm2.TPMSPCRSelection{Hash: b, PCRSelect: tpm2.PCClientCompatible.PCRs(uint(i))} + + pcrselections := []tpm2.TPMSPCRSelection{s2} + selection := tpm2.TPMLPCRSelection{PCRSelections: pcrselections} + //fmt.Printf("PCR selection is %v\n", selection) + + pcrreadresponse, err := tpm2.PCRRead{PCRSelectionIn: selection}.Execute(tpm) + if err != nil { + //rtn := tpm2taErrorReturn{fmt.Sprintf("Could not read PCRs with error %v", err.Error())} + //return c.JSON(http.StatusUnprocessableEntity, rtn) + fmt.Printf("PCR %v on Bank %v does not exist\n", i, b) + } else { + + pcrvalues := *pcrreadresponse + digests := pcrvalues.PCRValues.Digests[0] + digestsAsString := digests.Buffer + + ashex := fmt.Sprintf("%x", digestsAsString) + fmt.Printf(" PCRValues are %v => %v\n", reflect.TypeOf(ashex), ashex) + pcrvs[i] = ashex + } + + //results = append(results, *pcrreadresponse) + } + banks[bankNames[b]] = pcrvs + } + + return c.JSON(http.StatusOK, banks) +} + +// IGNORE THIS CODE; IT WORKS SO I AM NOT TOUCHING IT + +// func xNewPCRs(c echo.Context) error { +// fmt.Println("NEW tpm2 pcrs called") + +// tpm, err := openTPM("/dev/tpmrm0") +// if err != nil { +// rtn := tpm2taErrorReturn{fmt.Sprintf("Could not open tpm with error %v", err.Error())} +// return c.JSON(http.StatusUnprocessableEntity, rtn) +// } +// fmt.Printf("TPM device open by linuxtranport is %v\n", tpm) + +// s1 := tpm2.TPMSPCRSelection{Hash: tpm2.TPMAlgSHA1, PCRSelect: tpm2.PCClientCompatible.PCRs(0)} +// s2 := tpm2.TPMSPCRSelection{Hash: tpm2.TPMAlgSHA256, PCRSelect: tpm2.PCClientCompatible.PCRs(0)} + +// pcrselections := []tpm2.TPMSPCRSelection{s1, s2} +// selection := tpm2.TPMLPCRSelection{PCRSelections: pcrselections} +// fmt.Printf("PCR selection is %v\n", selection) + +// pcrreadresponse, err := tpm2.PCRRead{PCRSelectionIn: selection}.Execute(tpm) +// fmt.Printf("PCR pcrreadresponse is %w, %v\n", err, pcrreadresponse) + +// //tpm2.PCRSelections{[]tpm2.PCRSelection{Hash: "sha256", PCRSelect: []byte{0, 1, 2, 3}}} + +// return c.JSON(http.StatusOK, pcrreadresponse) +// } diff --git a/tarzan/tpm2/quote.go b/tarzan/tpm2/quote.go new file mode 100644 index 0000000..ffda63a --- /dev/null +++ b/tarzan/tpm2/quote.go @@ -0,0 +1,174 @@ +//go:build !windows + +package tpm2 + +import ( + "encoding/base64" + "fmt" + + "net/http" + "reflect" + "strconv" + "strings" + + "github.com/labstack/echo/v4" + + "github.com/google/go-tpm/tpm2" + "github.com/google/go-tpm/tpmutil" +) + +func NewQuote(c echo.Context) error { + + // Honestly this code is freaking awful + // but probably not as bad as PCRReadResponse + + fmt.Println("NEW quote called") + + // Obtain the parameters + ps := new(map[string]interface{}) + + if err := c.Bind(&ps); err != nil { + fmt.Printf("NewQuote BIND err %v\n", err.Error()) + rtn := tpm2taErrorReturn{fmt.Sprintf("Could not decode parameters %v", err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + + params := *ps + fmt.Printf("%v\n", params) + + // Here we parse the tpm2 device + // We have a default of /dev/tpm0 + tpm2device := params["tpm2/device"].(string) + + tpm, err := OpenTPM(tpm2device) + if err != nil { + rtn := tpm2taErrorReturn{fmt.Sprintf("Could not open specified TPM %v during Quote function with error %v", tpm2device, err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + + // Here we parse the bank + b := params["bank"].(string) + pcrbank := bankValues[b] + fmt.Printf("pcrbank %v\n", pcrbank) + + // These need to be integrated to generate the PCRSelections, of type []tpm2.TPMSPCRSelection + + // Here we parse the pcrSelection to obtain the []int structure for the pcrselections + s := strings.Split(params["pcrSelection"].(string), ",") + fmt.Printf("pcr selection string: %v\n", s) + + // TPM PCR Selection stuff fixed: https://github.com/google/go-tpm/issues/407 + + var indcies = make([]uint, len(s)) + for i, r := range s { + v, err := strconv.ParseUint(r, 10, 8) + if err != nil { + rtn := tpm2taErrorReturn{fmt.Sprintf("Unable to parse PCRSelection %v in selection %s", v, s)} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + indcies[i] = uint(v) + } + + pcrSelection := tpm2.TPMSPCRSelection{ + Hash: pcrbank, + PCRSelect: tpm2.PCClientCompatible.PCRs(indcies...), + } + + pcrselectionlist := tpm2.TPMLPCRSelection{PCRSelections: []tpm2.TPMSPCRSelection{pcrSelection}} + fmt.Printf("PCRselectionlist is %v\n", pcrselectionlist) + + // Here we parse the nonce + // If none then one will be generated + nonce := params["tpm2/nonce"].(string) + fmt.Printf("Received nonce is %v\n", nonce) + decodedNonce, err := base64.StdEncoding.DecodeString(nonce) + if err != nil { + rtn := tpm2taErrorReturn{fmt.Sprintf("Unable base64 undecode provided nonce %v with error %v", nonce, err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + nonceTPM2B := tpm2.TPM2BData{Buffer: decodedNonce} + + // Here we parse the akhandle + // This is a bit ugly but...that's the way go does things + // Strip the 0x, parse it as a Uint in base 16 with size 32 - returns a unit64, convert to a uint32 and then create the TPM handle + akh := strings.Replace(params["tpm2/akhandle"].(string), "0x", "", -1) + fmt.Printf("akh is %v\n", akh) + h, err := strconv.ParseUint(akh, 16, 32) + if err != nil { + rtn := tpm2taErrorReturn{fmt.Sprintf("Unable to parse AK handle %v", err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + h32 := uint32(h) // this is safe because we only create a 32bit unsigned value above. + + signingHandle := tpmutil.Handle(h32) + namedHandle := tpm2.NamedHandle{ + Handle: tpm2.TPMHandle(signingHandle), + Name: tpm2.TPM2BName{}, // This seems to work....? + } + + // This sets up the signing scheme, which is always RSASSA/SHA256 + + scheme := tpm2.TPMTSigScheme{ + Scheme: tpm2.TPMAlgRSASSA, + Details: tpm2.NewTPMUSigScheme( + tpm2.TPMAlgRSASSA, + &tpm2.TPMSSchemeHash{ + HashAlg: tpm2.TPMAlgSHA256, + }, + ), + } + + // Here's the quote + + quoteresponse, err := tpm2.Quote{SignHandle: namedHandle, QualifyingData: nonceTPM2B, InScheme: scheme, PCRSelect: pcrselectionlist}.Execute(tpm) + if err != nil { + fmt.Printf("Could not make Quote with error %v\n", err.Error()) + + rtn := tpm2taErrorReturn{fmt.Sprintf("Could not make Quote with error %v", err.Error())} + return c.JSON(http.StatusUnprocessableEntity, rtn) + } + + q := *quoteresponse + var quotepart tpm2.TPM2B[tpm2.TPMSAttest, *tpm2.TPMSAttest] + quotepart = q.Quoted // see type above :-) + signaturepart := q.Signature // of type tpm2.TPMSSignature + quotecontents, _ := quotepart.Contents() + + fmt.Println("********************") + fmt.Printf("Received nonce is %v\n", nonce) + fmt.Printf(" type : %v\n", reflect.TypeOf(quotecontents.ExtraData)) + fmt.Printf("buffer type : %v\n", reflect.TypeOf(quotecontents.ExtraData.Buffer)) + fmt.Printf("as hex : %x\n", quotecontents.ExtraData.Buffer) + fmt.Printf("as str : %v\n", string(quotecontents.ExtraData.Buffer)) + fmt.Printf("as nor : %v\n\n", quotecontents.ExtraData.Buffer) + fmt.Println("********************") + + quoteinfo, _ := quotecontents.Attested.Quote() + attested := attested{ + fmt.Sprintf("%v", quoteinfo.PCRSelect), + //fmt.Sprintf("%x", quoteinfo.PCRDigest.Buffer), + fmt.Sprintf("%v", base64.StdEncoding.EncodeToString(quoteinfo.PCRDigest.Buffer)), + } + clockinfo := clockInfo{ + fmt.Sprintf("%v", quotecontents.ClockInfo.Clock), + fmt.Sprintf("%v", quotecontents.ClockInfo.ResetCount), + fmt.Sprintf("%v", quotecontents.ClockInfo.RestartCount), + fmt.Sprintf("%v", quotecontents.ClockInfo.Safe), + } + + fmt.Printf("Quote contents\n Magic, Type %v,%v \n", quotecontents.Magic, quotecontents.Type) + + qstr := quoteStructure{ + //Magic: string(quotecontents.Magic), + Magic: fmt.Sprintf("%0x", quotecontents.Magic), + Type: fmt.Sprintf("%0x", quotecontents.Type), + QualifiedSigner: fmt.Sprintf("%x", base64.StdEncoding.EncodeToString(quotecontents.QualifiedSigner.Buffer)), + ExtraData: fmt.Sprintf("%v", base64.StdEncoding.EncodeToString(quotecontents.ExtraData.Buffer)), + FirmwareVersion: fmt.Sprintf("%x", quotecontents.FirmwareVersion), + ClockInfo: clockinfo, + Attested: attested, + } + fmt.Printf("QSTR is %v\n", qstr) + + return c.JSON(http.StatusOK, tpm2quoteReturn{qstr, signaturepart}) +} diff --git a/tarzan/uefi/endpoints.go b/tarzan/uefi/endpoints.go new file mode 100644 index 0000000..aaaf9dc --- /dev/null +++ b/tarzan/uefi/endpoints.go @@ -0,0 +1,137 @@ +package uefi + +import ( + "encoding/base64" + "fmt" + "io/ioutil" + "net/http" + _ "reflect" + + utilities "ta10/common" + + "github.com/labstack/echo/v4" + + "github.com/0x5a17ed/itkit/itlib" + _ "github.com/0x5a17ed/uefi/efi/efiguid" + "github.com/0x5a17ed/uefi/efi/efivario" + "github.com/0x5a17ed/uefi/efi/efivars" +) + +const UEFIEVENTLOGLOCATION string = "/sys/kernel/security/tpm0/binary_bios_measurements" + +type returnEventLog struct { + EventLog string `json:"eventlog"` + Encoding string `json:"encoded"` + UnEncodedLength int `json:"unencodedlength"` + EncodedLength int `json:"encodedlength"` +} + +func GetEventLogLocation(loc string) string { + fmt.Printf("UEFI Log requested from %v, unsafe mode is %v, giving: ", loc, utilities.IsUnsafe()) + + if utilities.IsUnsafe() == true { + fmt.Printf("%v\n", loc) + return loc + } else { + fmt.Printf("%v\n", UEFIEVENTLOGLOCATION) + return UEFIEVENTLOGLOCATION + } +} + +func Eventlog(c echo.Context) error { + fmt.Println("eventlog called") + + var postbody map[string]interface{} + var rtnbody = make(map[string]interface{}) + + if err := c.Bind(&postbody); err != nil { + rtnbody["postbody"] = err.Error() + return c.JSON(http.StatusUnprocessableEntity, rtnbody) + } + + u := GetEventLogLocation(fmt.Sprintf("%v", postbody["uefi/eventlog"])) + + fcontent, err := ioutil.ReadFile(u) + if err != nil { + rtnbody["file err"] = err.Error() + return c.JSON(http.StatusInternalServerError, rtnbody) + } + scontent := base64.StdEncoding.EncodeToString(fcontent) + + rtn := returnEventLog{scontent, "base64", len(fcontent), len(scontent)} + return c.JSON(http.StatusOK, rtn) +} + +type efivardata struct { + Name string `json:"name"` + Guid string `json:"guid"` + Attributes int32 `json:"attributes"` + SomeValue int `json:"somevalue"` // no idea what this is supposed to represent + Value string `json:"value"` + ErrorValue string `json:"errorvalue"` +} + +type returnEfivars struct { + Efivars []efivardata `json:"efivars"` + Count int `json:"count"` +} + +func Efivars(c echo.Context) error { + fmt.Println("efivars called") + + var efivars = []efivardata{} + + co := efivario.NewDefaultContext() + vni, _ := co.VariableNames() + + itlib.Apply(vni.Iter(), func(v efivario.VariableNameItem) { + hint, err := co.GetSizeHint(v.Name, v.GUID) + if err != nil || hint < 0 { + hint = 8 + } + + out := make([]byte, hint) + a, i, err := co.Get(v.Name, v.GUID, out) + //fmt.Printf("N=%v, A=%v, I=%v, E=%v, S=%v, O=%v, X=%v\n\n",v.Name,a,i,err,string(out[:]),out,err) + //fmt.Printf("Types %v, %v, %v, %v, %v\n",reflect.TypeOf(v.Name),reflect.TypeOf(v.GUID.String()), reflect.TypeOf(int32(a)), reflect.TypeOf(i), reflect.TypeOf(string(out[:]))) + errval := "" + if err != nil { + errval = err.Error() + } + + efd := efivardata{v.Name, v.GUID.String(), int32(a), i, string(out[:]), errval} + + fmt.Printf("X=%v\n\n", efd) + + efivars = append(efivars, efd) + }) + + rtn := returnEfivars{efivars, len(efivars)} + + return c.JSON(http.StatusOK, rtn) +} + +type returnBootInformation struct { + Message string `json:"msg"` +} + +func BootConfig(c echo.Context) error { + fmt.Println("boot order called") + + co := efivario.NewDefaultContext() + + v1, v2, v3 := efivars.BootCurrent.Get(co) + fmt.Printf("EFIbootcurrent %v\n%v\n%v\n", v1, v2, v3) + + ov1, ov2, ov3 := efivars.BootOrder.Get(co) + fmt.Printf("EFIbootorder %v\n%v\n%v\n", ov1, ov2, ov3) + + bv1, bv2, bv3 := efivars.BootNext.Get(co) + fmt.Printf("EFIbootnext %v\n%v\n%v\n", bv1, bv2, bv3) + + rtn := returnBootInformation{"boot order not implemented yet"} + + fmt.Printf("rtn=%v\n", rtn) + + return c.JSON(http.StatusOK, rtn) +}