From 0b7a72805acf2c8cb9b39e03a857a19259c59ea1 Mon Sep 17 00:00:00 2001 From: ThatSilentCoder <184309164+ThatSilentCoder@users.noreply.github.com> Date: Tue, 1 Apr 2025 09:18:21 -0400 Subject: [PATCH 1/9] [#896] Add basic Platform Certificate Class Registry support to the ACA (#898) * issue_896: first cut at changing the logic on the validator * issue_896: Added more javadocs, still going through the process and figuring out places where this will work. Can successfully debug provisioner+aca. * issue_896: slowly introducing component identifier v2 into multiple spots throughout out the app. Seems like we need to ensure that when we try to parse the pc from the identity claim, it needs to recognize the new kind of identifier. * issue_896: deleted abstract plat form config class, replaced it with plat config v1 (which already exists), moved attribuutes associated with v2 to the v2 class, when validating the aca will now verify if the platform config associated with the cert is v1 or v2. Made corrections to attributes names to better align with tcg docs. * issue_896:Added a new property to component info, made some more spelling corrections, deleted unused classes that were being referenced by componentinfo. pretty much done with the aca side of things. * issue_896:I believe I have finished the issue. Further testing needs to be done. Will put in a WIP PR for now. * issue_896: Made some more changes after viewing PR * issue_896: Changed v3 to v4 in the github actions yaml files. * issue_896: Fixed issues in one of the test classes, can now test other aspects of the SupplyChainCredentialValidator class. Will add more tests as more issues get fixed. * issue_896: Hopefully GITHUB actions will be more forgiving. * issue_896: Placed test task in the root build.gradle. Made more fixes to the test classes. * issue_896: Realized there might be more work needed for the validation part. Started adding more logic to validation. * issue_896: Last change before the long weekend. Hoping these changes will make github actions happy. * issue_896: Verifying that this part works. We will need to figure out a smart/efficient way of comparing the components from platform cert and device info report. * testing * v3_issue_896: Should work for this PR. * v3_issue_821: fixed the NPE issue we were getting during provisioning for missing component info. * v3_issue_896: my copy/paste skills need work. Fixed the issue that was causing the docker tests to fail. * v3_issue_896: trying to see if reverting the return call null will make a difference. * v3_issue_896: should fix issues with pc found on certain devices * v3_issue_896: part ii of should fix issues with pc found on certain devices --- .github/workflows/create_aca_images.yml | 251 +-- .../dotnet_provisioner_unit_tests.yml | 5 +- .github/workflows/hirs_package_linux.yml | 105 +- .github/workflows/hirs_unit_tests.yml | 161 +- .github/workflows/rim_tests.yml | 5 +- .github/workflows/system_test.yml | 3 +- HIRS_AttestationCA/build.gradle | 6 +- ...estfulAttestationCertificateAuthority.java | 2 +- .../certificate/ComponentResult.java | 59 +- .../certificate/PlatformCredential.java | 83 +- .../attributes/ComponentAddress.java | 2 +- .../attributes/ComponentClass.java | 6 + .../attributes/ComponentIdentifier.java | 28 +- .../attributes/PlatformConfiguration.java | 108 - .../attributes/PlatformConfigurationV1.java | 99 +- .../attributes/V2/AttributeStatus.java | 2 +- .../attributes/V2/CertificateIdentifier.java | 11 + .../attributes/V2/ComponentIdentifierV2.java | 101 +- .../V2/PlatformConfigurationV2.java | 123 +- .../userdefined/info/ComponentInfo.java | 82 +- .../entity/userdefined/info/FirmwareInfo.java | 4 +- .../entity/userdefined/info/HardwareInfo.java | 10 +- .../entity/userdefined/info/NetworkInfo.java | 2 +- .../entity/userdefined/info/OSInfo.java | 8 +- .../entity/userdefined/info/TPMInfo.java | 16 +- .../info/component/BIOSComponentInfo.java | 30 - .../component/BaseboardComponentInfo.java | 32 - .../info/component/ChassisComponentInfo.java | 32 - .../component/HardDriveComponentInfo.java | 32 - .../info/component/MemoryComponentInfo.java | 32 - .../info/component/NICComponentInfo.java | 32 - .../component/ProcessorComponentInfo.java | 32 - .../info/component/package-info.java | 1 - .../persist/provision/AbstractProcessor.java | 34 +- .../provision/IdentityClaimProcessor.java | 90 +- .../helper/CredentialManagementHelper.java | 38 +- .../service/SupplyChainValidationService.java | 9 +- .../persist/service/ValidationService.java | 10 +- .../attestationca/persist/util/AcaPciIds.java | 6 +- .../CertificateAttributeScvValidator.java | 265 ++- .../validation/CredentialValidator.java | 9 +- .../SupplyChainCredentialValidator.java | 43 +- .../certificate/PlatformCredentialTest.java | 61 +- .../attributes/ComponentClassTest.java | 228 +- .../SupplyChainCredentialValidatorTest.java | 1833 ++++++++++------- HIRS_AttestationCAPortal/build.gradle | 4 - .../CertificatePageController.java | 49 +- .../utils/CertificateStringMapBuilder.java | 43 +- HIRS_Structs/build.gradle | 4 - HIRS_Utils/build.gradle | 4 - build.gradle | 17 +- .../java/hirs/swid/TestSwidTagGateway.java | 85 +- 52 files changed, 2413 insertions(+), 1924 deletions(-) delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfiguration.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BIOSComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BaseboardComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ChassisComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/HardDriveComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/MemoryComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/NICComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ProcessorComponentInfo.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/package-info.java diff --git a/.github/workflows/create_aca_images.yml b/.github/workflows/create_aca_images.yml index 12677cb2..35322ddb 100644 --- a/.github/workflows/create_aca_images.yml +++ b/.github/workflows/create_aca_images.yml @@ -1,3 +1,4 @@ +# Updated: 02/11/2025 name: Create ACA Docker Image on: release: @@ -17,7 +18,7 @@ env: PUBLIC_IMAGE_NAME: ghcr.io/nsacyber/hirs/aca PUBLIC_IMAGE_TAG_LATEST: ghcr.io/nsacyber/hirs/aca:latest TAG_LATEST: ${{ github.event_name == 'release' || inputs.also_tag_latest }} # The public docker image will be tagged 'latest' for releases, or if this option is manually selected. -jobs: +jobs: setup: runs-on: ubuntu-latest outputs: @@ -27,44 +28,44 @@ jobs: WINDOWS_COMPAT_IMAGE_TAG: ${{ steps.setenv.outputs.WINDOWS_COMPAT_IMAGE_TAG }} PUBLIC_IMAGE_TAG: ${{ steps.setenv.outputs.PUBLIC_IMAGE_TAG }} steps: - - name: Set env - id: setenv - shell: bash - run: | - # Parse docker image tag from GitHub tag if available - if [ "${{ github.ref_type }}" = "tag" ]; then - # tags start with refs/tags/. Also remove v if it exists. - export IMAGE_TAG_VAR=${GITHUB_REF:10} - export IMAGE_TAG_VAR=${IMAGE_TAG_VAR//v/} - else - # Not a tag, use the commit hash. Do not tag as latest. - export IMAGE_TAG_VAR=${GITHUB_SHA:0:7} - fi - # To lowercase - export IMAGE_TAG_VAR=${IMAGE_TAG_VAR,,} - - # Save to output - echo "IMAGE_TAG=$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" - echo "ROCKY_IMAGE_TAG=$IMAGE_NAME_ROCKY:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" - echo "WINDOWS_IMAGE_TAG=$IMAGE_NAME_WINDOWS:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" - echo "WINDOWS_COMPAT_IMAGE_TAG=$IMAGE_NAME_WINDOWS_COMPAT:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" - echo "PUBLIC_IMAGE_TAG=$PUBLIC_IMAGE_NAME:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" - - name: Print env - run: | - echo GITHUB_REF_NAME=${{ github.ref_name }} - echo DOCKERFILE_ROCKY=$DOCKERFILE_ROCKY - echo DOCKERFILE_WINDOWS=$DOCKERFILE_WINDOWS - echo IMAGE_NAME_ROCKY=$IMAGE_NAME_ROCKY - echo IMAGE_NAME_WINDOWS=$IMAGE_NAME_WINDOWS - echo IMAGE_NAME_WINDOWS_COMPAT=$IMAGE_NAME_WINDOWS_COMPAT - echo PUBLIC_IMAGE_NAME=$PUBLIC_IMAGE_NAME - echo PUBLIC_IMAGE_TAG_LATEST=$PUBLIC_IMAGE_TAG_LATEST - echo TAG_LATEST=$TAG_LATEST - echo IMAGE_TAG=${{ steps.setenv.outputs.IMAGE_TAG }} - echo ROCKY_IMAGE_TAG=${{ steps.setenv.outputs.ROCKY_IMAGE_TAG }} - echo WINDOWS_IMAGE_TAG=${{ steps.setenv.outputs.WINDOWS_IMAGE_TAG }} - echo WINDOWS_COMPAT_IMAGE_TAG=${{ steps.setenv.outputs.WINDOWS_COMPAT_IMAGE_TAG }} - echo PUBLIC_IMAGE_TAG=${{ steps.setenv.outputs.PUBLIC_IMAGE_TAG }} + - name: Set env + id: setenv + shell: bash + run: | + # Parse docker image tag from GitHub tag if available + if [ "${{ github.ref_type }}" = "tag" ]; then + # tags start with refs/tags/. Also remove v if it exists. + export IMAGE_TAG_VAR=${GITHUB_REF:10} + export IMAGE_TAG_VAR=${IMAGE_TAG_VAR//v/} + else + # Not a tag, use the commit hash. Do not tag as latest. + export IMAGE_TAG_VAR=${GITHUB_SHA:0:7} + fi + # To lowercase + export IMAGE_TAG_VAR=${IMAGE_TAG_VAR,,} + + # Save to output + echo "IMAGE_TAG=$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" + echo "ROCKY_IMAGE_TAG=$IMAGE_NAME_ROCKY:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" + echo "WINDOWS_IMAGE_TAG=$IMAGE_NAME_WINDOWS:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" + echo "WINDOWS_COMPAT_IMAGE_TAG=$IMAGE_NAME_WINDOWS_COMPAT:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" + echo "PUBLIC_IMAGE_TAG=$PUBLIC_IMAGE_NAME:$IMAGE_TAG_VAR" >> "$GITHUB_OUTPUT" + - name: Print env + run: | + echo GITHUB_REF_NAME=${{ github.ref_name }} + echo DOCKERFILE_ROCKY=$DOCKERFILE_ROCKY + echo DOCKERFILE_WINDOWS=$DOCKERFILE_WINDOWS + echo IMAGE_NAME_ROCKY=$IMAGE_NAME_ROCKY + echo IMAGE_NAME_WINDOWS=$IMAGE_NAME_WINDOWS + echo IMAGE_NAME_WINDOWS_COMPAT=$IMAGE_NAME_WINDOWS_COMPAT + echo PUBLIC_IMAGE_NAME=$PUBLIC_IMAGE_NAME + echo PUBLIC_IMAGE_TAG_LATEST=$PUBLIC_IMAGE_TAG_LATEST + echo TAG_LATEST=$TAG_LATEST + echo IMAGE_TAG=${{ steps.setenv.outputs.IMAGE_TAG }} + echo ROCKY_IMAGE_TAG=${{ steps.setenv.outputs.ROCKY_IMAGE_TAG }} + echo WINDOWS_IMAGE_TAG=${{ steps.setenv.outputs.WINDOWS_IMAGE_TAG }} + echo WINDOWS_COMPAT_IMAGE_TAG=${{ steps.setenv.outputs.WINDOWS_COMPAT_IMAGE_TAG }} + echo PUBLIC_IMAGE_TAG=${{ steps.setenv.outputs.PUBLIC_IMAGE_TAG }} rocky-image: needs: setup @@ -72,78 +73,78 @@ jobs: env: TAG: ${{ needs.setup.outputs.ROCKY_IMAGE_TAG }} steps: - - name: Checkout main - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push a release Docker image for ${{ github.repository }} - uses: docker/build-push-action@v5 - with: - context: "{{defaultContext}}:.ci/docker" - file: Dockerfile.${{env.DOCKERFILE_ROCKY}} - build-args: REF=${{ github.ref_name }} - tags: ${{env.TAG}} - push: true - + - name: Checkout main + uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push a release Docker image for ${{ github.repository }} + uses: docker/build-push-action@v5 + with: + context: "{{defaultContext}}:.ci/docker" + file: Dockerfile.${{env.DOCKERFILE_ROCKY}} + build-args: REF=${{ github.ref_name }} + tags: ${{env.TAG}} + push: true + windows-11-image: needs: setup runs-on: windows-latest env: TAG: ${{ needs.setup.outputs.WINDOWS_IMAGE_TAG }} steps: - - name: Checkout main - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Checkout main + uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build the docker image for ${{ github.repository }} + run: | + cd ./.ci/docker + docker build --build-arg REF=${{ github.ref_name }} -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} . + + - name: Push the docker image + run: | + docker push ${{env.TAG}} - - name: Build the docker image for ${{ github.repository }} - run: | - cd ./.ci/docker - docker build --build-arg REF=${{ github.ref_name }} -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} . - - - name: Push the docker image - run: | - docker push ${{env.TAG}} - windows-compat-image: # This job uses a different runner and build arg than the other windows job. needs: setup runs-on: windows-2019 env: TAG: ${{ needs.setup.outputs.WINDOWS_COMPAT_IMAGE_TAG }} steps: - - name: Checkout main - uses: actions/checkout@v4 + - name: Checkout main + uses: actions/checkout@v4 - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build the docker image for ${{ github.repository }} + run: | + cd ./.ci/docker + docker build --build-arg REF=${{ github.ref_name }} -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} --build-arg BASE_IMAGE_TAG=lts-windowsservercore-1809 . + + - name: Push the docker image + run: | + docker push ${{env.TAG}} + - - name: Build the docker image for ${{ github.repository }} - run: | - cd ./.ci/docker - docker build --build-arg REF=${{ github.ref_name }} -f ./Dockerfile.${{env.DOCKERFILE_WINDOWS}} -t ${{env.TAG}} --build-arg BASE_IMAGE_TAG=lts-windowsservercore-1809 . - - - name: Push the docker image - run: | - docker push ${{env.TAG}} - - manifest: - needs: [setup, rocky-image, windows-11-image, windows-compat-image] + needs: [ setup, rocky-image, windows-11-image, windows-compat-image ] runs-on: ubuntu-latest env: IMAGE1: ${{ needs.setup.outputs.ROCKY_IMAGE_TAG }} @@ -151,34 +152,34 @@ jobs: IMAGE3: ${{ needs.setup.outputs.WINDOWS_COMPAT_IMAGE_TAG }} PUB: ${{ needs.setup.outputs.PUBLIC_IMAGE_TAG }} steps: - - name: Print env - run: | - echo IMAGE1=${{env.IMAGE1}} - echo IMAGE2=${{env.IMAGE2}} - echo IMAGE3=${{env.IMAGE3}} - echo PUB=${{env.PUB}} - - - name: Checkout main - uses: actions/checkout@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Create a new manifest - run: | - docker manifest create ${{env.PUB}} --amend ${{env.IMAGE1}} --amend ${{env.IMAGE2}} --amend ${{env.IMAGE3}} - - - name: Push the new manifest - run: | - docker manifest push ${{env.PUB}} - - - name: Create and push manifest latest if selected - if: env.TAG_LATEST != 'false' - run: | - docker manifest create $PUBLIC_IMAGE_TAG_LATEST --amend $IMAGE1 --amend $IMAGE2 --amend $IMAGE3 - docker manifest push $PUBLIC_IMAGE_TAG_LATEST + - name: Print env + run: | + echo IMAGE1=${{env.IMAGE1}} + echo IMAGE2=${{env.IMAGE2}} + echo IMAGE3=${{env.IMAGE3}} + echo PUB=${{env.PUB}} + + - name: Checkout main + uses: actions/checkout@v4 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Create a new manifest + run: | + docker manifest create ${{env.PUB}} --amend ${{env.IMAGE1}} --amend ${{env.IMAGE2}} --amend ${{env.IMAGE3}} + + - name: Push the new manifest + run: | + docker manifest push ${{env.PUB}} + + - name: Create and push manifest latest if selected + if: env.TAG_LATEST != 'false' + run: | + docker manifest create $PUBLIC_IMAGE_TAG_LATEST --amend $IMAGE1 --amend $IMAGE2 --amend $IMAGE3 + docker manifest push $PUBLIC_IMAGE_TAG_LATEST diff --git a/.github/workflows/dotnet_provisioner_unit_tests.yml b/.github/workflows/dotnet_provisioner_unit_tests.yml index 603e4b31..6fa613dc 100644 --- a/.github/workflows/dotnet_provisioner_unit_tests.yml +++ b/.github/workflows/dotnet_provisioner_unit_tests.yml @@ -1,8 +1,9 @@ +# Updated: 02/11/2025 name: Dotnet Provisioner Unit Tests on: push env: - DOTNET_VERSION: '6.0' + DOTNET_VERSION: '8.0' jobs: dotnet_provisioner_unit_tests: name: Restore and Run Unit Tests @@ -97,7 +98,7 @@ jobs: Evaluator: name: Evaluate Tests - needs: [dotnet_provisioner_unit_tests] + needs: [ dotnet_provisioner_unit_tests ] runs-on: ubuntu-latest continue-on-error: false steps: diff --git a/.github/workflows/hirs_package_linux.yml b/.github/workflows/hirs_package_linux.yml index b8f04b06..5b7b5ca0 100644 --- a/.github/workflows/hirs_package_linux.yml +++ b/.github/workflows/hirs_package_linux.yml @@ -1,3 +1,4 @@ +# Updated: 02/11/2025 name: HIRS build and packages for Linux on: push: @@ -8,34 +9,34 @@ on: jobs: # run the package script for HIRS ACA, Provisioners, tcg_rim_tool, and tcg_eventlog_tool - Package_linux: + Package_linux: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - - uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - server-id: github # Value of the distributionManagement/repository/id field of the pom.xml - settings-path: ${{ github.workspace }} # location for the settings.xml file - - name: directory setup - run: | - mkdir -p artifacts/jars - mkdir -p artifacts/win - mkdir -p artifacts/win/hirstools - - name: install dependencies - run: | - sudo apt-get update - sudo apt-get install git curl nano cron mariadb-server - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 - - name: Execute Gradle build - run: | + - uses: actions/checkout@v4 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + - name: directory setup + run: | + mkdir -p artifacts/jars + mkdir -p artifacts/win + mkdir -p artifacts/win/hirstools + - name: install dependencies + run: | + sudo apt-get update + sudo apt-get install git curl nano cron mariadb-server + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + - name: Execute Gradle build + run: | ./gradlew build; ./gradlew bootWar; ./gradlew buildDeb; @@ -48,35 +49,35 @@ jobs: cp tools/tcg_rim_tool/build/distributions/*.zip artifacts/win cp tools/tcg_eventlog_tool/build/distributions/*.zip artifacts/win cp package/win/tcg-rim-tool/* artifacts/win/hirstools - - name: Archive RPM files - uses: actions/upload-artifact@v4 - with: - name: RPM_Files - path: HIRS_AttestationCAPortal/build/distributions/*.rpm - if-no-files-found: error - - name: Archive DEB files - uses: actions/upload-artifact@v4 - with: - name: DEB_Files - path: HIRS_AttestationCAPortal/build/distributions/*.deb - if-no-files-found: error - - name: War files - uses: actions/upload-artifact@v4 - with: - name: WAR_Files - path: HIRS_AttestationCAPortal/build/libs/HIRS_AttestationCAPortal.war - if-no-files-found: error - - name: JAR_Files - uses: actions/upload-artifact@v4 - with: - name: JAR_Files - path: artifacts/jars/ - if-no-files-found: error - - name: ZIP_Files - uses: actions/upload-artifact@v4 - with: - name: ZIP_Files - path: artifacts/win/ - if-no-files-found: error + - name: Archive RPM files + uses: actions/upload-artifact@v4 + with: + name: RPM_Files + path: HIRS_AttestationCAPortal/build/distributions/*.rpm + if-no-files-found: error + - name: Archive DEB files + uses: actions/upload-artifact@v4 + with: + name: DEB_Files + path: HIRS_AttestationCAPortal/build/distributions/*.deb + if-no-files-found: error + - name: War files + uses: actions/upload-artifact@v4 + with: + name: WAR_Files + path: HIRS_AttestationCAPortal/build/libs/HIRS_AttestationCAPortal.war + if-no-files-found: error + - name: JAR_Files + uses: actions/upload-artifact@v4 + with: + name: JAR_Files + path: artifacts/jars/ + if-no-files-found: error + - name: ZIP_Files + uses: actions/upload-artifact@v4 + with: + name: ZIP_Files + path: artifacts/win/ + if-no-files-found: error diff --git a/.github/workflows/hirs_unit_tests.yml b/.github/workflows/hirs_unit_tests.yml index 240edef9..09b97901 100644 --- a/.github/workflows/hirs_unit_tests.yml +++ b/.github/workflows/hirs_unit_tests.yml @@ -1,6 +1,5 @@ # This workflow will build HIRS, run unit tests, and create HIRS artifacts -# Updated: 8/15/23 - +# Updated: 02/11/2025 name: HIRS Build and Unit Test on: @@ -17,82 +16,82 @@ jobs: ACA_Provisioner_Unit_Tests: runs-on: ubuntu-latest # Configures the job to run on the latest version of an Ubuntu Linux runner steps: - - uses: actions/checkout@v3 # run v3 of actions/checkout action, which checks out your repository onto the runner - # Build will archive build reports and will create a failedFile if build is not successful - - name: Directory setup - run: | - mkdir -p artifacts/githubActionsResults - mkdir -p artifacts/upload_reports/HIRS_AttestationCA - mkdir -p artifacts/upload_reports/HIRS_AttestationCAPortal - mkdir -p artifacts/upload_reports/HIRS_Provisioner - mkdir -p artifacts/upload_reports/HIRS_ProvisionerTPM2 - mkdir -p artifacts/upload_reports/HIRS_Structs - mkdir -p artifacts/upload_reports/HIRS_Utils - mkdir -p artifacts/upload_reports/tcg_rim_tool - mkdir -p artifacts/upload_reports/tcg_eventlog_tool - # Run the provisioner and ACA unit tests via gradle build in a Rocky Docker container - - name: Build HIRS and run unit tests - run: | - - # log into and run docker (note: must set up secrets in github for ghcr username and access_token) - echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $ --password-stdin - - # docker run options: - # create a mount between curr directory on the runner and the HIRS folder created by the cloning of HIRS repo - # -v $(pwd):/HIRS - # image used for the container, given by : - # rocky8: ghcr.io/nsacyber/hirs/hirs-rocky8-ci:latest [repo: https://github.com/orgs/nsacyber/packages] - # bash commands to clean/build/test each subproject - # /bin/bash -c '' - docker run --rm \ - -v $(pwd):/HIRS \ - ghcr.io/nsacyber/hirs/hirs-rocky8-ci:latest /bin/bash -c \ - 'pushd /HIRS - gradle_status=0 - - # git added a feature that gives error if user is not owner of the top-level directory; need to override this - git config --global --add safe.directory /HIRS - - # clean, build and run unit tests on all sub-projects; copy build reports to an artifacts directory - ./gradlew :HIRS_AttestationCA:clean :HIRS_AttestationCA:build :HIRS_AttestationCA:test - if (( $? != "0" )) ; then gradle_status=1; fi - cp -r /HIRS/HIRS_AttestationCA/build/reports/ /HIRS/artifacts/upload_reports/HIRS_AttestationCA/. - ./gradlew :HIRS_AttestationCAPortal:clean :HIRS_AttestationCAPortal:build :HIRS_AttestationCAPortal:test - if (( $? != "0" )) ; then gradle_status=1; fi - cp -r /HIRS/HIRS_AttestationCAPortal/build/reports/ /HIRS/artifacts/upload_reports/HIRS_AttestationCAPortal/. - #./gradlew :HIRS_Provisioner:clean :HIRS_Provisioner:build :HIRS_Provisioner:test - #if (( $? != "0" )) ; then gradle_status=1; fi - #cp -r /HIRS/HIRS_Provisioner/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Provisioner/. - #./gradlew :HIRS_ProvisionerTPM2:clean :HIRS_ProvisionerTPM2:build :HIRS_ProvisionerTPM2:test - #if (( $? != "0" )) ; then gradle_status=1; fi - #cp -r /HIRS/HIRS_ProvisionerTPM2/docs/ /HIRS/artifacts/upload_reports/HIRS_ProvisionerTPM2/. - ./gradlew :HIRS_Structs:clean :HIRS_Structs:build :HIRS_Structs:test - if (( $? != "0" )) ; then gradle_status=1; fi - cp -r /HIRS/HIRS_Structs/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Structs/. - ./gradlew :HIRS_Utils:clean :HIRS_Utils:build :HIRS_Utils:test - if (( $? != "0" )) ; then gradle_status=1; fi - cp -r /HIRS/HIRS_Utils/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Utils/. - #./gradlew :TPM_Utils:clean :TPM_Utils:build :TPM_Utils:test - #if (( $? != "0" )) ; then gradle_status=1; fi - - # Create "fail file" to fail the Build ACA tests if gradle exited with anything other than 0 - if (( $gradle_status == "0" )) ; then - echo "In docker: Build Passed" - else - echo "In docker: Build Failed" - touch /HIRS/artifacts/githubActionsResults/buildFailed.txt - fi; popd;' - # Upload build report files - - name: Archive report files - uses: actions/upload-artifact@v4 - with: - name: HIRS_Build_Reports - path: artifacts/upload_reports/* - if-no-files-found: ignore - # If buildFailed file exists, use that to fail the ACA unit tests - - name: Check if build/test passed or failed - if: ${{ hashFiles('artifacts/githubActionsResults/buildFailed.txt') != '' }} - uses: actions/github-script@v6 - with: - script: | - core.setFailed('Build or Unit Test Failed') + - uses: actions/checkout@v4 # run v4 of actions/checkout action, which checks out your repository onto the runner + # Build will archive build reports and will create a failedFile if build is not successful + - name: Directory setup + run: | + mkdir -p artifacts/githubActionsResults + mkdir -p artifacts/upload_reports/HIRS_AttestationCA + mkdir -p artifacts/upload_reports/HIRS_AttestationCAPortal + mkdir -p artifacts/upload_reports/HIRS_Provisioner + mkdir -p artifacts/upload_reports/HIRS_ProvisionerTPM2 + mkdir -p artifacts/upload_reports/HIRS_Structs + mkdir -p artifacts/upload_reports/HIRS_Utils + mkdir -p artifacts/upload_reports/tcg_rim_tool + mkdir -p artifacts/upload_reports/tcg_eventlog_tool + # Run the provisioner and ACA unit tests via gradle build in a Rocky Docker container + - name: Build HIRS and run unit tests + run: | + + # log into and run docker (note: must set up secrets in github for ghcr username and access_token) + echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u $ --password-stdin + + # docker run options: + # create a mount between curr directory on the runner and the HIRS folder created by the cloning of HIRS repo + # -v $(pwd):/HIRS + # image used for the container, given by : + # rocky8: ghcr.io/nsacyber/hirs/hirs-rocky8-ci:latest [repo: https://github.com/orgs/nsacyber/packages] + # bash commands to clean/build/test each subproject + # /bin/bash -c '' + docker run --rm \ + -v $(pwd):/HIRS \ + ghcr.io/nsacyber/hirs/hirs-rocky8-ci:latest /bin/bash -c \ + 'pushd /HIRS + gradle_status=0 + + # git added a feature that gives error if user is not owner of the top-level directory; need to override this + git config --global --add safe.directory /HIRS + + # clean, build and run unit tests on all sub-projects; copy build reports to an artifacts directory + ./gradlew :HIRS_AttestationCA:clean :HIRS_AttestationCA:build :HIRS_AttestationCA:test + if (( $? != "0" )) ; then gradle_status=1; fi + cp -r /HIRS/HIRS_AttestationCA/build/reports/ /HIRS/artifacts/upload_reports/HIRS_AttestationCA/. + ./gradlew :HIRS_AttestationCAPortal:clean :HIRS_AttestationCAPortal:build :HIRS_AttestationCAPortal:test + if (( $? != "0" )) ; then gradle_status=1; fi + cp -r /HIRS/HIRS_AttestationCAPortal/build/reports/ /HIRS/artifacts/upload_reports/HIRS_AttestationCAPortal/. + #./gradlew :HIRS_Provisioner:clean :HIRS_Provisioner:build :HIRS_Provisioner:test + #if (( $? != "0" )) ; then gradle_status=1; fi + #cp -r /HIRS/HIRS_Provisioner/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Provisioner/. + #./gradlew :HIRS_ProvisionerTPM2:clean :HIRS_ProvisionerTPM2:build :HIRS_ProvisionerTPM2:test + #if (( $? != "0" )) ; then gradle_status=1; fi + #cp -r /HIRS/HIRS_ProvisionerTPM2/docs/ /HIRS/artifacts/upload_reports/HIRS_ProvisionerTPM2/. + ./gradlew :HIRS_Structs:clean :HIRS_Structs:build :HIRS_Structs:test + if (( $? != "0" )) ; then gradle_status=1; fi + cp -r /HIRS/HIRS_Structs/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Structs/. + ./gradlew :HIRS_Utils:clean :HIRS_Utils:build :HIRS_Utils:test + if (( $? != "0" )) ; then gradle_status=1; fi + cp -r /HIRS/HIRS_Utils/build/reports/ /HIRS/artifacts/upload_reports/HIRS_Utils/. + #./gradlew :TPM_Utils:clean :TPM_Utils:build :TPM_Utils:test + #if (( $? != "0" )) ; then gradle_status=1; fi + + # Create "fail file" to fail the Build ACA tests if gradle exited with anything other than 0 + if (( $gradle_status == "0" )) ; then + echo "In docker: Build Passed" + else + echo "In docker: Build Failed" + touch /HIRS/artifacts/githubActionsResults/buildFailed.txt + fi; popd;' + # Upload build report files + - name: Archive report files + uses: actions/upload-artifact@v4 + with: + name: HIRS_Build_Reports + path: artifacts/upload_reports/* + if-no-files-found: ignore + # If buildFailed file exists, use that to fail the ACA unit tests + - name: Check if build/test passed or failed + if: ${{ hashFiles('artifacts/githubActionsResults/buildFailed.txt') != '' }} + uses: actions/github-script@v6 + with: + script: | + core.setFailed('Build or Unit Test Failed') \ No newline at end of file diff --git a/.github/workflows/rim_tests.yml b/.github/workflows/rim_tests.yml index 11799391..c45e6d34 100644 --- a/.github/workflows/rim_tests.yml +++ b/.github/workflows/rim_tests.yml @@ -1,4 +1,5 @@ # workflow is used to run RIM tests +# Updated: 02/11/2025 name: RIM Test on: push: @@ -28,7 +29,7 @@ jobs: sudo apt-get update sudo apt-get install git curl nano cron mariadb-server - name: Setup Gradle - uses: gradle/actions/setup-gradle@v3 + uses: gradle/actions/setup-gradle@v4 - name: Execute Gradle build run: | ./gradlew build; @@ -37,7 +38,7 @@ jobs: run: | sudo dpkg -i tools/tcg_rim_tool/build/distributions/tcg-rim-tool*.deb - name: RIM tests - run: | + run: | ./.ci/tcg-rim-tool/scripts/run_all_tests.sh --verbose diff --git a/.github/workflows/system_test.yml b/.github/workflows/system_test.yml index cb8b44e0..ab5167bb 100644 --- a/.github/workflows/system_test.yml +++ b/.github/workflows/system_test.yml @@ -1,6 +1,5 @@ # This workflow will build HIRS, run system tests, and create artifacts consisting of ACA and Provisioner logs. -# Updated: 06/05/2024 -# +# Updated: 02/11/2025 name: HIRS System Tests on: push: diff --git a/HIRS_AttestationCA/build.gradle b/HIRS_AttestationCA/build.gradle index dfe5a908..88f24280 100644 --- a/HIRS_AttestationCA/build.gradle +++ b/HIRS_AttestationCA/build.gradle @@ -65,8 +65,4 @@ sourceSets { srcDir '../HIRS_Provisioner.NET/hirs/Resources' } } -} - -test { - useJUnitPlatform() -} +} \ No newline at end of file diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/RestfulAttestationCertificateAuthority.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/RestfulAttestationCertificateAuthority.java index db00267d..1cc40302 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/RestfulAttestationCertificateAuthority.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/RestfulAttestationCertificateAuthority.java @@ -108,7 +108,7 @@ public class RestfulAttestationCertificateAuthority extends AttestationCertifica * the client's desired attestation key, if the correct nonce is supplied. * * @param certificateRequest request containing nonce from earlier identity - * * claim handshake + * claim handshake * @return The response to the client provisioner. */ @Override diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/ComponentResult.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/ComponentResult.java index 01eef415..5ce0127e 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/ComponentResult.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/ComponentResult.java @@ -98,7 +98,7 @@ public class ComponentResult extends ArchivableEntity { * * @param boardSerialNumber associated platform certificate serial number. * @param certificateSerialNumber unique number associated with header info. - * @param certificateType parameter holds version 1.2 or 2.0. + * @param certificateType type of certificate. parameter holds version 1.2 or 2.0. * @param componentIdentifier object with information from the platform certificate components. */ public ComponentResult(final String boardSerialNumber, final String certificateSerialNumber, @@ -116,28 +116,51 @@ public class ComponentResult extends ArchivableEntity { } StringBuilder sb = new StringBuilder(); - for (ComponentAddress element : componentIdentifier.getComponentAddress()) { + for (ComponentAddress element : componentIdentifier.getComponentAddresses()) { + sb.append(String.format("%s:%s;", element.getAddressTypeValue(), + element.getAddressValue().toString())); + } + componentAddress = sb.toString(); + } + + /** + * @param boardSerialNumber associated platform certificate serial number + * @param certificateSerialNumber unique number associated with header info + * @param certificateType type of certificate. Parameter holds version 1.2 or 2.0. + * @param componentIdentifierV2 version 2 component identifier + */ + public ComponentResult(final String boardSerialNumber, final String certificateSerialNumber, + final String certificateType, + final ComponentIdentifierV2 componentIdentifierV2) { + + this.boardSerialNumber = boardSerialNumber; + this.certificateSerialNumber = certificateSerialNumber; + this.certificateType = certificateType; + this.manufacturer = componentIdentifierV2.getComponentManufacturer().toString(); + this.model = componentIdentifierV2.getComponentModel().toString(); + this.serialNumber = componentIdentifierV2.getComponentSerial().toString(); + this.revisionNumber = componentIdentifierV2.getComponentRevision().toString(); + if (componentIdentifierV2.getFieldReplaceable() != null) { + this.fieldReplaceable = componentIdentifierV2.getFieldReplaceable().isTrue(); + } + + StringBuilder sb = new StringBuilder(); + for (ComponentAddress element : componentIdentifierV2.getComponentAddresses()) { sb.append(String.format("%s:%s;", element.getAddressTypeValue(), element.getAddressValue().toString())); } componentAddress = sb.toString(); - // V2 fields - if (componentIdentifier.isVersion2() - && componentIdentifier instanceof ComponentIdentifierV2 ciV2) { - // this is a downside of findbugs, the code is set up to indicate if a CI is V2 or not - // but find bugs is throwing a flag because instanceof isn't being used. - this.componentClassValue = ciV2.getComponentClass().getComponentIdentifier(); - this.componentClassStr = ciV2.getComponentClass().toString(); - this.componentClassType = ciV2.getComponentClass().getRegistryType(); - this.attributeStatus = ciV2.getAttributeStatus(); - this.version2 = true; - if (ciV2.getCertificateIdentifier() != null) { - this.issuerDN = ciV2.getCertificateIdentifier().getIssuerDN().toString(); - if (ciV2.getComponentPlatformUri() != null) { - this.uniformResourceIdentifier = ciV2.getComponentPlatformUri() - .getUniformResourceIdentifier().toString(); - } + this.componentClassValue = componentIdentifierV2.getComponentClass().getComponentIdentifier(); + this.componentClassStr = componentIdentifierV2.getComponentClass().toString(); + this.componentClassType = componentIdentifierV2.getComponentClass().getRegistryType(); + this.attributeStatus = componentIdentifierV2.getAttributeStatus(); + this.version2 = true; + if (componentIdentifierV2.getComponentPlatformCert() != null) { + this.issuerDN = componentIdentifierV2.getComponentPlatformCert().getIssuerDN().toString(); + if (componentIdentifierV2.getComponentPlatformCertUri() != null) { + this.uniformResourceIdentifier = componentIdentifierV2.getComponentPlatformCertUri() + .getUniformResourceIdentifier().toString(); } } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java index e11ab146..4a7d654f 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredential.java @@ -2,10 +2,10 @@ package hirs.attestationca.persist.entity.userdefined.certificate; import com.google.common.base.Preconditions; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; -import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfigurationV1; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -64,25 +64,30 @@ public class PlatformCredential extends DeviceAssociatedCertificate { * TCPA Trusted Platform Endorsement. */ public static final String CERTIFICATE_TYPE_1_2 = "TCPA Trusted Platform Endorsement"; + /** * TCG Trusted Platform Endorsement. */ public static final String CERTIFICATE_TYPE_2_0 = "TCG Trusted Platform Endorsement"; private static final int TCG_SPECIFICATION_LENGTH = 3; + // These are Object Identifiers (OIDs) for sections in the credentials private static final String POLICY_QUALIFIER_CPSURI = "1.3.6.1.5.5.7.2.1"; private static final String POLICY_QUALIFIER_USER_NOTICE = "1.3.6.1.5.5.7.2.2"; + // OID for TCG Attributes private static final String PLATFORM_MANUFACTURER = "2.23.133.2.4"; private static final String PLATFORM_MODEL = "2.23.133.2.5"; private static final String PLATFORM_VERSION = "2.23.133.2.6"; private static final String PLATFORM_SERIAL = "2.23.133.2.23"; private static final String PLATFORM_BASEBOARD_CHASSIS_COMBINED = "2.23.133.5.1.6"; + // OID for TCG Platform Class Common Attributes private static final String PLATFORM_MANUFACTURER_2_0 = "2.23.133.5.1.1"; private static final String PLATFORM_MODEL_2_0 = "2.23.133.5.1.4"; private static final String PLATFORM_VERSION_2_0 = "2.23.133.5.1.5"; private static final String PLATFORM_SERIAL_2_0 = "2.23.133.5.1.6"; + // OID for Certificate Attributes private static final String TCG_PLATFORM_SPECIFICATION = "2.23.133.2.17"; private static final String TPM_SECURITY_ASSERTION = "2.23.133.2.18"; @@ -255,8 +260,8 @@ public class PlatformCredential extends DeviceAssociatedCertificate { /** * Verify if the AlgorithmIdentifiers are equal. * - * @param id1 AlgorithIdentifier one - * @param id2 AlgorithIdentifier two + * @param id1 Algorithm Identifier one + * @param id2 Algorithm Identifier two * @return True if are the same, False if not */ public static boolean isAlgIdEqual(final AlgorithmIdentifier id1, @@ -349,6 +354,9 @@ public class PlatformCredential extends DeviceAssociatedCertificate { return verifier.verify(attCert.getSignatureValue().getOctets()); } + /** + * Parses the Platform Certificate fields. + */ private void parseFields() throws IOException { AttributeCertificateInfo certificate = getAttributeCertificate().getAcinfo(); Map policyQualifier = getPolicyQualifier(certificate); @@ -403,7 +411,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Parse a 1.2 Platform Certificate (Attribute Certificate). + * Parses a 1.2 Platform Certificate (Attribute Certificate). * * @param certificate Attribute Certificate */ @@ -456,7 +464,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Parse a 2.0 Platform Certificate (Attribute Certificate). + * Parses a 2.0 Platform Certificate (Attribute Certificate). * * @param certificate Attribute Certificate */ @@ -505,7 +513,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Get the x509 Platform Certificate version. + * Retrieves the x509 Platform Certificate version. * * @return a big integer representing the certificate version. */ @@ -524,7 +532,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Get the cPSuri from the Certificate Policies. + * Retrieves the cPSuri from the Certificate Policies. * * @return cPSuri from the CertificatePolicies. * @throws IOException when reading the certificate. @@ -540,7 +548,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Get the Platform Configuration Attribute from the Platform Certificate. + * Retrieves the Platform Configuration Attribute from the Platform Certificate. * * @return a map with all the attributes * @throws IllegalArgumentException when there is a parsing error @@ -550,8 +558,11 @@ public class PlatformCredential extends DeviceAssociatedCertificate { throws IllegalArgumentException, IOException { Map attributes = new HashMap<>(); ASN1Sequence attributeSequence; + + ASN1Encodable[] asn1EncodableArray = getAttributeCertificate().getAcinfo().getAttributes().toArray(); + // Check all attributes for Platform Configuration - for (ASN1Encodable enc : getAttributeCertificate().getAcinfo().getAttributes().toArray()) { + for (ASN1Encodable enc : asn1EncodableArray) { Attribute attr = Attribute.getInstance(enc); attributeSequence = ASN1Sequence.getInstance(attr.getAttrValues().getObjectAt(0)); @@ -582,8 +593,7 @@ public class PlatformCredential extends DeviceAssociatedCertificate { break; default: // No class defined for this attribute - log.warn("No class defined for attribute with OID: " - + attr.getAttrType().getId()); + log.warn("No class defined for attribute with OID: {}", attr.getAttrType().getId()); break; } } @@ -610,12 +620,30 @@ public class PlatformCredential extends DeviceAssociatedCertificate { * @throws IllegalArgumentException when there is a parsing error * @throws IOException when reading the certificate. */ - public PlatformConfiguration getPlatformConfiguration() + public PlatformConfigurationV1 getPlatformConfigurationV1() throws IllegalArgumentException, IOException { if (getAttribute("platformConfiguration") != null - && getAttribute("platformConfiguration") instanceof PlatformConfiguration) { - return (PlatformConfiguration) getAttribute("platformConfiguration"); + && getAttribute("platformConfiguration") instanceof PlatformConfigurationV1) { + return (PlatformConfigurationV1) getAttribute("platformConfiguration"); + } + + return null; + } + + /** + * Get the Version 2 Platform Configuration Attribute from the Platform Certificate. + * + * @return a map with the Version 2 Platform Configuration information. + * @throws IllegalArgumentException when there is a parsing error + * @throws IOException when reading the certificate. + */ + public PlatformConfigurationV2 getPlatformConfigurationV2() + throws IllegalArgumentException, IOException { + + if (getAttribute("platformConfiguration") != null + && getAttribute("platformConfiguration") instanceof PlatformConfigurationV2) { + return (PlatformConfigurationV2) getAttribute("platformConfiguration"); } return null; @@ -684,20 +712,39 @@ public class PlatformCredential extends DeviceAssociatedCertificate { } /** - * Get the list of component identifiers if there are any. + * Retrieves the list of component identifiers if there are any. * * @return the list of component identifiers if there are any */ public List getComponentIdentifiers() { try { - PlatformConfiguration platformConfig = getPlatformConfiguration(); + PlatformConfigurationV1 platformConfig = getPlatformConfigurationV1(); if (platformConfig != null) { - return platformConfig.getComponentIdentifier(); + return platformConfig.getComponentIdentifiers(); } } catch (IOException e) { - log.error("Unable to parse Platform Configuration from Credential or find" + log.error("Unable to parse Platform Configuration from Platform Credential or find" + "component identifiers"); } return Collections.emptyList(); } + + /** + * Retrieves the list of version 2 component identifiers if there are any. + * + * @return the list of version 2 component identifiers if there are any + */ + public List getComponentIdentifiersV2() { + try { + PlatformConfigurationV2 platformConfigV2 = getPlatformConfigurationV2(); + + if (platformConfigV2 != null) { + return platformConfigV2.getComponentIdentifiers(); + } + } catch (IOException e) { + log.error("Unable to parse Platform Configuration Version 2 from Platform Credential or find" + + "version 2 component identifiers"); + } + return Collections.emptyList(); + } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentAddress.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentAddress.java index 2f9f82a9..7284b08d 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentAddress.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentAddress.java @@ -8,7 +8,7 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1UTF8String; /** - * Basic class that handle component addresses from the component identifier. + * Basic class that represents the component addresses from the component identifier object. *
  * componentAddress ::= SEQUENCE {
  *      addressType AddressType,
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClass.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClass.java
index 7256a6b8..4987e95f 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClass.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClass.java
@@ -33,6 +33,10 @@ ComponentClass {
 
     private static final String SMBIOS_COMPONENT_REGISTRY = "2.23.133.18.3.3";
 
+    private static final String PCIE_BASED_COMPONENT_REGISTRY = "2.23.133.18.3.4";
+
+    private static final String STORAGE_COMPONENT_REGISTRY = "2.23.133.18.3.5";
+
     private static final Path WINDOWS_JSON_PATH = FileSystems.getDefault().getPath(
             "C:/", "ProgramData", "hirs", "aca", "default-properties", "component-class.json");
 
@@ -122,6 +126,8 @@ ComponentClass {
         this.registryType = switch (registryOid) {
             case TCG_COMPONENT_REGISTRY -> "TCG";
             case SMBIOS_COMPONENT_REGISTRY -> "SMBIOS";
+            case PCIE_BASED_COMPONENT_REGISTRY -> "PCIE";
+            case STORAGE_COMPONENT_REGISTRY -> "STORAGE";
             default -> UNKNOWN_STRING;
         };
 
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentIdentifier.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentIdentifier.java
index 7b56a283..d0549c9e 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentIdentifier.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentIdentifier.java
@@ -16,8 +16,8 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 /**
- * Basic class that handle component identifiers from the Platform Configuration
- * Attribute.
+ * Basic class that represents version 1 of the component identifiers from the Version 1
+ * Platform Configuration Attribute.
  * 
  * ComponentIdentifier ::= SEQUENCE {
  *      componentManufacturer UTF8String (SIZE (1..STRMAX)),
@@ -26,7 +26,7 @@ import java.util.stream.Collectors;
  *      componentRevision [1] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
  *      componentManufacturerId [2] IMPLICIT PrivateEnterpriseNumber OPTIONAL,
  *      fieldReplaceable [3] IMPLICIT BOOLEAN OPTIONAL,
- *      componentAddress [4] IMPLICIT
+ *      componentAddresses [4] IMPLICIT
  *          SEQUENCE(SIZE(1..CONFIGMAX)) OF ComponentAddress OPTIONAL}
  * where STRMAX is 256, CONFIGMAX is 32
  * 
@@ -80,7 +80,7 @@ public class ComponentIdentifier { private ASN1Boolean fieldReplaceable; - private List componentAddress; + private List componentAddresses; private boolean validationResult = true; @@ -94,7 +94,7 @@ public class ComponentIdentifier { componentRevision = new DERUTF8String(NOT_SPECIFIED_COMPONENT); componentManufacturerId = null; fieldReplaceable = null; - componentAddress = new ArrayList<>(); + componentAddresses = new ArrayList<>(); } /** @@ -106,7 +106,7 @@ public class ComponentIdentifier { * @param componentRevision represents the component revision * @param componentManufacturerId represents the component manufacturer ID * @param fieldReplaceable represents if the component is replaceable - * @param componentAddress represents a list of addresses + * @param componentAddresses represents a list of addresses */ public ComponentIdentifier(final DERUTF8String componentManufacturer, final DERUTF8String componentModel, @@ -114,14 +114,14 @@ public class ComponentIdentifier { final DERUTF8String componentRevision, final ASN1ObjectIdentifier componentManufacturerId, final ASN1Boolean fieldReplaceable, - final List componentAddress) { + final List componentAddresses) { this.componentManufacturer = componentManufacturer; this.componentModel = componentModel; this.componentSerial = componentSerial; this.componentRevision = componentRevision; this.componentManufacturerId = componentManufacturerId; this.fieldReplaceable = fieldReplaceable; - this.componentAddress = componentAddress.stream().toList(); + this.componentAddresses = componentAddresses.stream().toList(); } /** @@ -160,7 +160,7 @@ public class ComponentIdentifier { break; case COMPONENT_ADDRESS: ASN1Sequence addressesSequence = ASN1Sequence.getInstance(taggedObj, false); - componentAddress = retrieveComponentAddress(addressesSequence); + componentAddresses = retrieveComponentAddress(addressesSequence); break; default: throw new IllegalArgumentException("Component identifier contains " @@ -229,14 +229,16 @@ public class ComponentIdentifier { if (fieldReplaceable != null) { sb.append(fieldReplaceable); } - sb.append(", componentAddress="); - if (!componentAddress.isEmpty()) { - sb.append(componentAddress + sb.append(", componentAddresses="); + if (!componentAddresses.isEmpty()) { + sb.append(componentAddresses .stream() .map(Object::toString) .collect(Collectors.joining(","))); } - sb.append(", certificateIdentifier="); + if (sb.charAt(sb.length() - 1) == ',') { + sb.deleteCharAt(sb.length() - 1); + } sb.append("}"); return sb.toString(); diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfiguration.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfiguration.java deleted file mode 100644 index 9680dc92..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfiguration.java +++ /dev/null @@ -1,108 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.certificate.attributes; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * Abstract class that provides base info for Platform Configuration of - * the Platform Certificate Attribute. - */ -@AllArgsConstructor -public abstract class PlatformConfiguration { - private ArrayList componentIdentifier = new ArrayList<>(); - @Getter - @Setter - private URIReference componentIdentifierUri; - private ArrayList platformProperties = new ArrayList<>(); - @Getter - @Setter - private URIReference platformPropertiesUri; - - /** - * Default constructor. - */ - public PlatformConfiguration() { - this.componentIdentifier = new ArrayList<>(); - this.componentIdentifierUri = null; - this.platformProperties = new ArrayList<>(); - this.platformPropertiesUri = null; - } - - /** - * Constructor given the Platform Configuration values. - * - * @param componentIdentifier list containing all the components inside the - * Platform Configuration. - * @param platformProperties list containing all the properties inside the - * Platform Configuration. - * @param platformPropertiesUri object containing the URI Reference - */ - public PlatformConfiguration(final List componentIdentifier, - final List platformProperties, - final URIReference platformPropertiesUri) { - this.componentIdentifier = new ArrayList<>(componentIdentifier); - this.platformProperties = new ArrayList<>(platformProperties); - this.platformPropertiesUri = platformPropertiesUri; - } - - /** - * @return the componentIdentifier - */ - public List getComponentIdentifier() { - return Collections.unmodifiableList(componentIdentifier); - } - - /** - * @param componentIdentifier the componentIdentifier to set - */ - public void setComponentIdentifier(final List componentIdentifier) { - this.componentIdentifier = new ArrayList<>(componentIdentifier); - } - - /** - * Add function for the component identifier array. - * - * @param componentIdentifier object to add - * @return status of the add, if successful or not - */ - protected boolean add(final ComponentIdentifier componentIdentifier) { - if (this.componentIdentifier != null) { - return this.componentIdentifier.add(componentIdentifier); - } - - return false; - } - - /** - * @return the platformProperties - */ - public List getPlatformProperties() { - return Collections.unmodifiableList(platformProperties); - } - - /** - * @param platformProperties the platformProperties to set - */ - public void setPlatformProperties(final List platformProperties) { - this.platformProperties = new ArrayList<>(platformProperties); - } - - /** - * Add function for the platform property array. - * - * @param platformProperty property object to add - * @return status of the add, if successful or not - */ - protected boolean add(final PlatformProperty platformProperty) { - if (this.platformProperties != null) { - return this.platformProperties.add(platformProperty); - } - - return false; - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfigurationV1.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfigurationV1.java index c0dd0df6..757660b3 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfigurationV1.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/PlatformConfigurationV1.java @@ -1,28 +1,53 @@ package hirs.attestationca.persist.entity.userdefined.certificate.attributes; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; /** - * Basic class that handle Platform Configuration for the Platform Certificate + * Basic class that represents the Version 1 Platform Configuration used for the Platform Certificate * Attribute. *
  * PlatformConfiguration ::= SEQUENCE {
- *      componentIdentifier [0] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF
+ *      componentIdentifiers [0] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF
  *           ComponentIdentifier OPTIONAL,
  *      platformProperties [1] IMPLICIT SEQUENCE(SIZE(1..CONFIGMAX)) OF Properties OPTIONAL,
  *      platformPropertiesUri [2] IMPLICIT URIReference OPTIONAL }
  * 
*/ -public class PlatformConfigurationV1 extends PlatformConfiguration { +@AllArgsConstructor +public class PlatformConfigurationV1 { private static final int COMPONENT_IDENTIFIER = 0; + private static final int PLATFORM_PROPERTIES = 1; + private static final int PLATFORM_PROPERTIES_URI = 2; + private List componentIdentifiers; + + private List platformProperties; + + @Getter + @Setter + private URIReference platformPropertiesUri; + + /** + * Default constructor. + */ + public PlatformConfigurationV1() { + componentIdentifiers = new ArrayList<>(); + platformProperties = new ArrayList<>(); + platformPropertiesUri = null; + } + /** * Constructor given the SEQUENCE that contains Platform Configuration. * @@ -32,7 +57,7 @@ public class PlatformConfigurationV1 extends PlatformConfiguration { public PlatformConfigurationV1(final ASN1Sequence sequence) throws IllegalArgumentException { //Default values - setComponentIdentifier(new ArrayList<>()); + setComponentIdentifiers(new ArrayList<>()); setPlatformProperties(new ArrayList<>()); setPlatformPropertiesUri(null); @@ -42,7 +67,7 @@ public class PlatformConfigurationV1 extends PlatformConfiguration { //Set information based on the set tagged switch (taggedSequence.getTagNo()) { case COMPONENT_IDENTIFIER: - //Get componentIdentifier + //Get componentIdentifiers ASN1Sequence componentConfiguration = ASN1Sequence.getInstance(taggedSequence, false); @@ -77,6 +102,62 @@ public class PlatformConfigurationV1 extends PlatformConfiguration { } } + /** + * @return list of version 1 component identifiers + */ + public List getComponentIdentifiers() { + return Collections.unmodifiableList(componentIdentifiers); + } + + /** + * @param componentIdentifiers list of version 1 component identifiers + */ + public void setComponentIdentifiers(final List componentIdentifiers) { + this.componentIdentifiers = new ArrayList<>(componentIdentifiers); + } + + /** + * Add function for the version 1 component identifier array. + * + * @param componentIdentifier object to add + * @return status of the add, if successful or not + */ + protected boolean add(final ComponentIdentifier componentIdentifier) { + if (this.componentIdentifiers != null) { + return this.componentIdentifiers.add(componentIdentifier); + } + + return false; + } + + /** + * @return the platformProperties + */ + public List getPlatformProperties() { + return Collections.unmodifiableList(platformProperties); + } + + /** + * @param platformProperties the platformProperties to set + */ + public void setPlatformProperties(final List platformProperties) { + this.platformProperties = new ArrayList<>(platformProperties); + } + + /** + * Add function for the platform property array. + * + * @param platformProperty property object to add + * @return status of the add, if successful or not + */ + protected boolean add(final PlatformProperty platformProperty) { + if (this.platformProperties != null) { + return this.platformProperties.add(platformProperty); + } + + return false; + } + /** * Creates a string representation of the Platform Configuration V1 object. * @@ -86,15 +167,15 @@ public class PlatformConfigurationV1 extends PlatformConfiguration { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("PlatformConfiguration{"); - sb.append("componentIdentifier="); - if (getComponentIdentifier().size() > 0) { - sb.append(getComponentIdentifier() + sb.append("componentIdentifiers="); + if (!getComponentIdentifiers().isEmpty()) { + sb.append(getComponentIdentifiers() .stream() .map(Object::toString) .collect(Collectors.joining(","))); } sb.append(", platformProperties="); - if (getPlatformProperties().size() > 0) { + if (!getPlatformProperties().isEmpty()) { sb.append(getPlatformProperties() .stream() .map(Object::toString) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/AttributeStatus.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/AttributeStatus.java index 5a5b9b03..d9ea0999 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/AttributeStatus.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/AttributeStatus.java @@ -16,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; * removed (2) } *
*/ +@Getter @AllArgsConstructor public enum AttributeStatus { /** @@ -35,6 +36,5 @@ public enum AttributeStatus { */ EMPTY_STATUS(StringUtils.EMPTY); - @Getter private final String value; } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/CertificateIdentifier.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/CertificateIdentifier.java index 2512d498..2a00f9ca 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/CertificateIdentifier.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/CertificateIdentifier.java @@ -76,6 +76,12 @@ public class CertificateIdentifier { } } + /** + * Helper method that parses the attribute certificate id from the provided attribute + * certificate ASN1 Sequence. + * + * @param attrCertSeq ASN1 attribute certificate sequence + */ private void parseAttributeCertId(final ASN1Sequence attrCertSeq) { //Check if it have a valid number of identifiers if (attrCertSeq.size() != SEQUENCE_NUMBER) { @@ -87,6 +93,11 @@ public class CertificateIdentifier { hashSigValue = attrCertSeq.getObjectAt(1).toString(); } + /** + * Helper method that parses the generic certificate id from the provided issuer serial ASN1 sequence. + * + * @param issuerSerialSeq ASN1 issuer serial sequence + */ private void parseGenericCertId(final ASN1Sequence issuerSerialSeq) { //Check if it have a valid number of identifiers if (issuerSerialSeq.size() != SEQUENCE_NUMBER) { diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/ComponentIdentifierV2.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/ComponentIdentifierV2.java index e7b4aa5b..88dbceab 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/ComponentIdentifierV2.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/ComponentIdentifierV2.java @@ -20,17 +20,18 @@ import java.util.List; import java.util.stream.Collectors; /** - * Basic class that handle component identifiers from the Platform Configuration - * Attribute. + * Basic class that represents version 2 of the component identifiers from the Version 2 + * Platform Configuration Attribute. *
  * ComponentIdentifier ::= SEQUENCE {
+ *      componentClass ComponentClass
  *      componentManufacturer UTF8String (SIZE (1..STRMAX)),
  *      componentModel UTF8String (SIZE (1..STRMAX)),
  *      componentSerial[0] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
  *      componentRevision [1] IMPLICIT UTF8String (SIZE (1..STRMAX)) OPTIONAL,
  *      componentManufacturerId [2] IMPLICIT PrivateEnterpriseNumber OPTIONAL,
  *      fieldReplaceable [3] IMPLICIT BOOLEAN OPTIONAL,
- *      componentAddress [4] IMPLICIT
+ *      componentAddresses [4] IMPLICIT
  *          SEQUENCE(SIZE(1..CONFIGMAX)) OF ComponentAddress OPTIONAL
  *      componentPlatformCert [5] IMPLICIT CertificateIdentifier OPTIONAL,
  *      componentPlatformCertUri [6] IMPLICIT URIReference OPTIONAL,
@@ -48,15 +49,15 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
     // Additional optional identifiers for version 2
     private static final int COMPONENT_PLATFORM_CERT = 5;
 
-    private static final int COMPONENT_PLATFORM_URI = 6;
+    private static final int COMPONENT_PLATFORM_CERT_URI = 6;
 
     private static final int ATTRIBUTE_STATUS = 7;
 
     private ComponentClass componentClass;
 
-    private CertificateIdentifier certificateIdentifier;
+    private CertificateIdentifier componentPlatformCert;
 
-    private URIReference componentPlatformUri;
+    private URIReference componentPlatformCertUri;
 
     private AttributeStatus attributeStatus;
 
@@ -66,25 +67,25 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
     public ComponentIdentifierV2() {
         super();
         componentClass = new ComponentClass();
-        certificateIdentifier = null;
-        componentPlatformUri = null;
+        componentPlatformCert = null;
+        componentPlatformCertUri = null;
         attributeStatus = AttributeStatus.EMPTY_STATUS;
     }
 
     /**
      * Constructor given the components values.
      *
-     * @param componentClass          represent the component type
-     * @param componentManufacturer   represents the component manufacturer
-     * @param componentModel          represents the component model
-     * @param componentSerial         represents the component serial number
-     * @param componentRevision       represents the component revision
-     * @param componentManufacturerId represents the component manufacturer ID
-     * @param fieldReplaceable        represents if the component is replaceable
-     * @param componentAddress        represents a list of addresses
-     * @param certificateIdentifier   object representing certificate Id
-     * @param componentPlatformUri    object containing the URI Reference
-     * @param attributeStatus         object containing enumerated status
+     * @param componentClass           represent the component type
+     * @param componentManufacturer    represents the component manufacturer
+     * @param componentModel           represents the component model
+     * @param componentSerial          represents the component serial number
+     * @param componentRevision        represents the component revision
+     * @param componentManufacturerId  represents the component manufacturer ID
+     * @param fieldReplaceable         represents if the component is replaceable
+     * @param componentAddress         represents a list of addresses
+     * @param componentPlatformCert    object representing certificate Id
+     * @param componentPlatformCertUri object containing the URI Reference
+     * @param attributeStatus          object containing enumerated status
      */
     public ComponentIdentifierV2(final ComponentClass componentClass,
                                  final DERUTF8String componentManufacturer,
@@ -94,16 +95,16 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
                                  final ASN1ObjectIdentifier componentManufacturerId,
                                  final ASN1Boolean fieldReplaceable,
                                  final List componentAddress,
-                                 final CertificateIdentifier certificateIdentifier,
-                                 final URIReference componentPlatformUri,
+                                 final CertificateIdentifier componentPlatformCert,
+                                 final URIReference componentPlatformCertUri,
                                  final AttributeStatus attributeStatus) {
         super(componentManufacturer, componentModel, componentSerial,
                 componentRevision, componentManufacturerId, fieldReplaceable,
                 componentAddress);
         this.componentClass = componentClass;
         // additional optional component identifiers
-        this.certificateIdentifier = certificateIdentifier;
-        this.componentPlatformUri = componentPlatformUri;
+        this.componentPlatformCert = componentPlatformCert;
+        this.componentPlatformCertUri = componentPlatformCertUri;
         this.attributeStatus = attributeStatus;
     }
 
@@ -150,15 +151,15 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
                     break;
                 case COMPONENT_ADDRESS:
                     ASN1Sequence addressesSequence = ASN1Sequence.getInstance(taggedObj, false);
-                    this.setComponentAddress(retrieveComponentAddress(addressesSequence));
+                    this.setComponentAddresses(retrieveComponentAddress(addressesSequence));
                     break;
                 case COMPONENT_PLATFORM_CERT:
                     ASN1Sequence ciSequence = ASN1Sequence.getInstance(taggedObj, false);
-                    certificateIdentifier = new CertificateIdentifier(ciSequence);
+                    componentPlatformCert = new CertificateIdentifier(ciSequence);
                     break;
-                case COMPONENT_PLATFORM_URI:
+                case COMPONENT_PLATFORM_CERT_URI:
                     ASN1Sequence uriSequence = ASN1Sequence.getInstance(taggedObj, false);
-                    this.componentPlatformUri = new URIReference(uriSequence);
+                    this.componentPlatformCertUri = new URIReference(uriSequence);
                     break;
                 case ATTRIBUTE_STATUS:
                     ASN1Enumerated enumerated = ASN1Enumerated.getInstance(taggedObj, false);
@@ -172,34 +173,6 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
         }
     }
 
-    /**
-     * @return true if the component has been modified.
-     */
-    public final boolean isAdded() {
-        return getAttributeStatus() == AttributeStatus.ADDED;
-    }
-
-    /**
-     * @return true if the component has been modified.
-     */
-    public final boolean isModified() {
-        return getAttributeStatus() == AttributeStatus.MODIFIED;
-    }
-
-    /**
-     * @return true if the component has been removed.
-     */
-    public final boolean isRemoved() {
-        return getAttributeStatus() == AttributeStatus.REMOVED;
-    }
-
-    /**
-     * @return true if the component status wasn't set.
-     */
-    public final boolean isEmpty() {
-        return (getAttributeStatus() == AttributeStatus.EMPTY_STATUS)
-                || (getAttributeStatus() == null);
-    }
 
     /**
      * @return indicates the type of platform certificate.
@@ -238,20 +211,20 @@ public class ComponentIdentifierV2 extends ComponentIdentifier {
         if (getFieldReplaceable() != null) {
             sb.append(getFieldReplaceable());
         }
-        sb.append(", componentAddress=");
-        if (getComponentAddress().size() > 0) {
-            sb.append(getComponentAddress()
+        sb.append(", componentAddresses=");
+        if (!getComponentAddresses().isEmpty()) {
+            sb.append(getComponentAddresses()
                     .stream()
                     .map(Object::toString)
                     .collect(Collectors.joining(",")));
         }
-        sb.append(", certificateIdentifier=");
-        if (certificateIdentifier != null) {
-            sb.append(certificateIdentifier);
+        sb.append(", componentPlatformCert=");
+        if (componentPlatformCert != null) {
+            sb.append(componentPlatformCert);
         }
-        sb.append(", componentPlatformUri=");
-        if (componentPlatformUri != null) {
-            sb.append(componentPlatformUri);
+        sb.append(", componentPlatformCertUri=");
+        if (componentPlatformCertUri != null) {
+            sb.append(componentPlatformCertUri);
         }
         sb.append(", status=");
         if (attributeStatus != null) {
diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/PlatformConfigurationV2.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/PlatformConfigurationV2.java
index 58dd341d..58c2f454 100644
--- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/PlatformConfigurationV2.java
+++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/V2/PlatformConfigurationV2.java
@@ -1,15 +1,20 @@
 package hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2;
 
-import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration;
+import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformProperty;
 import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
 import org.bouncycastle.asn1.ASN1Sequence;
 import org.bouncycastle.asn1.ASN1TaggedObject;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
- * Basic class that handle Platform Configuration for the Platform Certificate
+ * Basic class that represents the Version 2 Platform Configuration used for the Platform Certificate
  * Attribute.
  * 
  * PlatformConfiguration ::= SEQUENCE {
@@ -20,23 +25,49 @@ import java.util.stream.Collectors;
  *      platformPropertiesUri [3] IMPLICIT URIReference OPTIONAL }
  * 
*/ -public class PlatformConfigurationV2 extends PlatformConfiguration { +@AllArgsConstructor +public class PlatformConfigurationV2 { private static final int COMPONENT_IDENTIFIER = 0; + private static final int COMPONENT_IDENTIFIER_URI = 1; + private static final int PLATFORM_PROPERTIES = 2; + private static final int PLATFORM_PROPERTIES_URI = 3; + private List componentIdentifiers; + + @Getter + @Setter + private URIReference componentIdentifiersUri; + + private List platformProperties; + + @Getter + @Setter + private URIReference platformPropertiesUri; + /** - * Constructor given the SEQUENCE that contains Platform Configuration. + * Default constructor. + */ + public PlatformConfigurationV2() { + componentIdentifiers = new ArrayList<>(); + componentIdentifiersUri = null; + platformProperties = new ArrayList<>(); + platformPropertiesUri = null; + } + + /** + * Constructor given the SEQUENCE that contains version 2 Platform Configuration. * - * @param sequence containing the the Platform Configuration. - * @throws IllegalArgumentException if there was an error on the parsing + * @param sequence containing the version 2 Platform Configuration. + * @throws IllegalArgumentException if there was an error while parsing */ public PlatformConfigurationV2(final ASN1Sequence sequence) throws IllegalArgumentException { //Default values - setComponentIdentifier(new ArrayList<>()); - setComponentIdentifierUri(null); + setComponentIdentifiers(new ArrayList<>()); + setComponentIdentifiersUri(null); setPlatformProperties(new ArrayList<>()); setPlatformPropertiesUri(null); @@ -62,7 +93,7 @@ public class PlatformConfigurationV2 extends PlatformConfiguration { //Get componentIdentifierURI ASN1Sequence componentUri = ASN1Sequence.getInstance(taggedSequence, false); //Save Component Identifier URI - setComponentIdentifierUri(new URIReference(componentUri)); + setComponentIdentifiersUri(new URIReference(componentUri)); break; case PLATFORM_PROPERTIES: //Get platformProperties @@ -87,6 +118,64 @@ public class PlatformConfigurationV2 extends PlatformConfiguration { } } + /** + * @return a collection of version 2 component identifiers. + */ + public List getComponentIdentifiers() { + return Collections.unmodifiableList(componentIdentifiers); + } + + /** + * @param componentIdentifiers list of version 2 component identifiers + */ + public void setComponentIdentifiers( + final List componentIdentifiers) { + this.componentIdentifiers = new ArrayList<>(componentIdentifiers); + } + + + /** + * Add function for the component identifier array. + * + * @param componentIdentifierV2 object to add + * @return status of the add, if successful or not + */ + protected boolean add(final ComponentIdentifierV2 componentIdentifierV2) { + if (this.componentIdentifiers != null) { + return this.componentIdentifiers.add(componentIdentifierV2); + } + + return false; + } + + /** + * @return the platformProperties + */ + public List getPlatformProperties() { + return Collections.unmodifiableList(platformProperties); + } + + /** + * @param platformProperties the platformProperties to set + */ + public void setPlatformProperties(final List platformProperties) { + this.platformProperties = new ArrayList<>(platformProperties); + } + + /** + * Add function for the platform property array. + * + * @param platformProperty property object to add + * @return status of the add, if successful or not + */ + protected boolean add(final PlatformProperty platformProperty) { + if (this.platformProperties != null) { + return this.platformProperties.add(platformProperty); + } + + return false; + } + /** * Creates a string representation of the Platform Configuration V2 object. * @@ -95,20 +184,20 @@ public class PlatformConfigurationV2 extends PlatformConfiguration { @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("PlatformConfiguration{"); - sb.append("componentIdentifier="); - if (getComponentIdentifier().size() > 0) { - sb.append(getComponentIdentifier() + sb.append("PlatformConfigurationV2{"); + sb.append("componentIdentifiers="); + if (!getComponentIdentifiers().isEmpty()) { + sb.append(getComponentIdentifiers() .stream() .map(Object::toString) .collect(Collectors.joining(","))); } - sb.append(", componentIdentifierUri="); - if (getComponentIdentifierUri() != null) { - sb.append(getComponentIdentifierUri()); + sb.append(", componentIdentifiersUri="); + if (getComponentIdentifiersUri() != null) { + sb.append(getComponentIdentifiersUri()); } sb.append(", platformProperties="); - if (getPlatformProperties().size() > 0) { + if (!getPlatformProperties().isEmpty()) { sb.append(getPlatformProperties() .stream() .map(Object::toString) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/ComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/ComponentInfo.java index aa98f282..fd540c75 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/ComponentInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/ComponentInfo.java @@ -55,10 +55,14 @@ public class ComponentInfo extends ArchivableEntity { @XmlElement @Column - private String componentClass; + private String componentClassValue; + + @XmlElement + @Column + private String componentClassRegistry; /** - * Base constructor for children. + * Constructor. * * @param componentManufacturer Component Manufacturer (must not be null) * @param componentModel Component Model (must not be null) @@ -87,24 +91,34 @@ public class ComponentInfo extends ArchivableEntity { final String componentModel, final String componentSerial, final String componentRevision) { - if (isComplete( - componentManufacturer, - componentModel, - componentSerial, - componentRevision)) { - log.error("ComponentInfo: manufacturer and/or " - + "model can not be null"); - throw new NullPointerException("ComponentInfo: manufacturer and/or " - + "model can not be null"); + + if (deviceName == null) { + log.error("Component Info's device name cannot be null."); + this.deviceName = ""; + } else { + this.deviceName = deviceName; } - this.deviceName = deviceName; - this.componentManufacturer = componentManufacturer.trim(); - this.componentModel = componentModel.trim(); + + if (componentManufacturer == null) { + log.error("Component Info's manufacturer cannot be null."); + this.componentManufacturer = ""; + } else { + this.componentManufacturer = componentManufacturer.trim(); + } + + if (componentModel == null) { + log.error("Component Info's model cannot be null."); + this.componentModel = ""; + } else { + this.componentModel = componentModel.trim(); + } + if (componentSerial != null) { this.componentSerial = componentSerial.trim(); } else { this.componentSerial = ComponentIdentifier.NOT_SPECIFIED_COMPONENT; } + if (componentRevision != null) { this.componentRevision = componentRevision.trim(); } else { @@ -115,44 +129,28 @@ public class ComponentInfo extends ArchivableEntity { /** * Constructor. * - * @param deviceName the host machine associated with this component. - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - * @param componentClass Component Class (can be null) + * @param deviceName the host machine associated with this component. + * @param componentManufacturer Component Manufacturer (must not be null) + * @param componentModel Component Model (must not be null) + * @param componentSerial Component Serial Number (can be null) + * @param componentRevision Component Revision or Version (can be null) + * @param componentClassValue Component Class Value (can be null) + * @param componentClassRegistry Component Class Registry (can be null) */ public ComponentInfo(final String deviceName, final String componentManufacturer, final String componentModel, final String componentSerial, final String componentRevision, - final String componentClass) { + final String componentClassValue, + final String componentClassRegistry) { this(deviceName, componentManufacturer, componentModel, componentSerial, componentRevision); - this.componentClass = Objects.requireNonNullElse(componentClass, StringUtils.EMPTY); + this.componentClassValue = Objects.requireNonNullElse(componentClassValue, StringUtils.EMPTY); + this.componentClassRegistry = Objects.requireNonNullElse(componentClassRegistry, StringUtils.EMPTY); } - /** - * Determines whether the given properties represent a - * ComponentInfo that will be useful in validation. - * Currently, only components which have a non-null - * manufacturer and model are considered valid. - * - * @param componentManufacturer a String containing a component's manufacturer - * @param componentModel a String representing a component's model - * @param componentSerial a String representing a component's serial number - * @param componentRevision a String representing a component's revision - * @return true if the component is valid, false if not - */ - public static boolean isComplete(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - return (StringUtils.isEmpty(componentManufacturer) - || StringUtils.isEmpty(componentModel)); - } /** * Returns a hash code that is associated with common fields for components. @@ -161,6 +159,6 @@ public class ComponentInfo extends ArchivableEntity { */ public int hashCommonElements() { return Objects.hash(componentManufacturer, componentModel, - componentSerial, componentRevision, componentClass); + componentSerial, componentRevision, componentClassValue, componentClassRegistry); } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/FirmwareInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/FirmwareInfo.java index 8921c108..78419922 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/FirmwareInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/FirmwareInfo.java @@ -19,11 +19,11 @@ import java.io.Serializable; public class FirmwareInfo implements Serializable { @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private final String biosVendor; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private final String biosVersion; @XmlElement diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/HardwareInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/HardwareInfo.java index 35a9bd7f..b9b379b1 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/HardwareInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/HardwareInfo.java @@ -22,11 +22,11 @@ import java.io.Serializable; public class HardwareInfo implements Serializable { @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private String manufacturer = DeviceInfoEnums.NOT_SPECIFIED; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private String productName = DeviceInfoEnums.NOT_SPECIFIED; @XmlElement @@ -34,15 +34,15 @@ public class HardwareInfo implements Serializable { private String version = DeviceInfoEnums.NOT_SPECIFIED; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private String systemSerialNumber = DeviceInfoEnums.NOT_SPECIFIED; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private String chassisSerialNumber = DeviceInfoEnums.NOT_SPECIFIED; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private String baseboardSerialNumber = DeviceInfoEnums.NOT_SPECIFIED; /** diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/NetworkInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/NetworkInfo.java index 73ec8d80..8993d3be 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/NetworkInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/NetworkInfo.java @@ -23,7 +23,7 @@ public class NetworkInfo implements Serializable { @XmlElement @Getter - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH) + @Column private String hostname; @XmlElement diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/OSInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/OSInfo.java index 285682df..218ce697 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/OSInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/OSInfo.java @@ -21,11 +21,11 @@ import java.io.Serializable; public class OSInfo implements Serializable { @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private final String osName; @XmlElement - @Column(length = DeviceInfoEnums.LONG_STRING_LENGTH, nullable = false) + @Column(nullable = false) private final String osVersion; @XmlElement @@ -33,11 +33,11 @@ public class OSInfo implements Serializable { private final String osArch; @XmlElement - @Column(length = DeviceInfoEnums.SHORT_STRING_LENGTH, nullable = true) + @Column(length = DeviceInfoEnums.SHORT_STRING_LENGTH) private final String distribution; @XmlElement - @Column(length = DeviceInfoEnums.SHORT_STRING_LENGTH, nullable = true) + @Column(length = DeviceInfoEnums.SHORT_STRING_LENGTH) private final String distributionRelease; /** diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/TPMInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/TPMInfo.java index 5ca240ff..55ec2b9e 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/TPMInfo.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/TPMInfo.java @@ -30,23 +30,23 @@ public class TPMInfo implements Serializable { private static final int MAX_BLOB_SIZE = 65535; @XmlElement - @Column(length = DeviceInfoEnums.MED_STRING_LENGTH, nullable = true) + @Column(length = DeviceInfoEnums.MED_STRING_LENGTH) private String tpmMake; @XmlElement - @Column(nullable = true) + @Column private short tpmVersionMajor; @XmlElement - @Column(nullable = true) + @Column private short tpmVersionMinor; @XmlElement - @Column(nullable = true) + @Column private short tpmVersionRevMajor; @XmlElement - @Column(nullable = true) + @Column private short tpmVersionRevMinor; /** @@ -60,13 +60,13 @@ public class TPMInfo implements Serializable { @JsonIgnore private X509Certificate identityCertificate; - @Column(nullable = true, columnDefinition = "blob") + @Column(columnDefinition = "blob") private byte[] pcrValues; - @Column(nullable = true, columnDefinition = "blob") + @Column(columnDefinition = "blob") private byte[] tpmQuoteHash; - @Column(nullable = true, columnDefinition = "blob") + @Column(columnDefinition = "blob") private byte[] tpmQuoteSignature; /** diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BIOSComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BIOSComponentInfo.java deleted file mode 100644 index c74fe65b..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BIOSComponentInfo.java +++ /dev/null @@ -1,30 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold BIOS/UEFI Component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.BIOS_UEFI) -public class BIOSComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public BIOSComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentRevision) { - super(componentManufacturer, componentModel, null, - componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BaseboardComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BaseboardComponentInfo.java deleted file mode 100644 index af975061..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/BaseboardComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold information about baseboard components. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.BASEBOARD) -public class BaseboardComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public BaseboardComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, componentSerial, - componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ChassisComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ChassisComponentInfo.java deleted file mode 100644 index b26a3f18..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ChassisComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold chassis component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.CHASSIS) -public class ChassisComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public ChassisComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, - componentSerial, componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/HardDriveComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/HardDriveComponentInfo.java deleted file mode 100644 index fe5f0846..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/HardDriveComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold hard drive component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.HARD_DRIVE) -public class HardDriveComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public HardDriveComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, - componentSerial, componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/MemoryComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/MemoryComponentInfo.java deleted file mode 100644 index 5e794601..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/MemoryComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold memory component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.MEMORY) -public class MemoryComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public MemoryComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, - componentSerial, componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/NICComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/NICComponentInfo.java deleted file mode 100644 index 8f15c72c..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/NICComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold Network Interface Card (NIC) component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.NIC) -public class NICComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public NICComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, - componentSerial, componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ProcessorComponentInfo.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ProcessorComponentInfo.java deleted file mode 100644 index a2d53f25..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/ProcessorComponentInfo.java +++ /dev/null @@ -1,32 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; - -import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; -import hirs.utils.enums.ComponentType; -import jakarta.persistence.DiscriminatorValue; -import jakarta.persistence.Entity; -import lombok.NoArgsConstructor; - -/** - * Class to hold processor component information. - */ -@NoArgsConstructor -@Entity -@DiscriminatorValue(value = ComponentType.Values.PROCESSOR) -public class ProcessorComponentInfo extends ComponentInfo { - - /** - * Constructor. - * - * @param componentManufacturer Component Manufacturer (must not be null) - * @param componentModel Component Model (must not be null) - * @param componentSerial Component Serial Number (can be null) - * @param componentRevision Component Revision or Version (can be null) - */ - public ProcessorComponentInfo(final String componentManufacturer, - final String componentModel, - final String componentSerial, - final String componentRevision) { - super(componentManufacturer, componentModel, - componentSerial, componentRevision); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/package-info.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/package-info.java deleted file mode 100644 index a7f24171..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/entity/userdefined/info/component/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package hirs.attestationca.persist.entity.userdefined.info.component; diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java index 087f4be1..0f0622b2 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java @@ -159,6 +159,7 @@ public class AbstractProcessor { final ProvisionerTpm2.IdentityClaim identityClaim, final PublicKey ekPub, final CertificateRepository certificateRepository) { EndorsementCredential endorsementCredential = null; + if (identityClaim.hasEndorsementCredential()) { endorsementCredential = CredentialManagementHelper.storeEndorsementCredential( certificateRepository, @@ -172,6 +173,7 @@ public class AbstractProcessor { log.warn("No endorsement credential was received in identity claim and no EK Public" + " Key was provided to check for uploaded certificates."); } + return endorsementCredential; } @@ -191,12 +193,21 @@ public class AbstractProcessor { final EndorsementCredential endorsementCredential, final CertificateRepository certificateRepository) { List platformCredentials = new LinkedList<>(); + if (identityClaim.getPlatformCredentialCount() > 0) { - for (ByteString platformCredential : identityClaim.getPlatformCredentialList()) { + + List platformCredentialList = identityClaim.getPlatformCredentialList(); + + for (ByteString platformCredential : platformCredentialList) { if (!platformCredential.isEmpty()) { - platformCredentials.add(CredentialManagementHelper.storePlatformCredential( - certificateRepository, platformCredential.toByteArray(), - identityClaim.getDv().getNw().getHostname())); + PlatformCredential storedPlatformCredential = + CredentialManagementHelper.storePlatformCredential( + certificateRepository, platformCredential.toByteArray(), + identityClaim.getDv().getNw().getHostname()); + + if (storedPlatformCredential != null) { + platformCredentials.add(storedPlatformCredential); + } } } } else if (endorsementCredential != null) { @@ -206,6 +217,7 @@ public class AbstractProcessor { } else { log.warn("No platform credential received in identity claim."); } + return platformCredentials; } @@ -219,7 +231,7 @@ public class AbstractProcessor { private EndorsementCredential getEndorsementCredential( final PublicKey ekPublicKey, final CertificateRepository certificateRepository) { - log.debug("Searching for endorsement credential based on public key: " + ekPublicKey); + log.debug("Searching for endorsement credential based on public key: {}", ekPublicKey); if (ekPublicKey == null) { throw new IllegalArgumentException("Cannot look up an EC given a null public key"); @@ -254,10 +266,8 @@ public class AbstractProcessor { * @param endorsementCredential the endorsement credential used to generate the AC * @param platformCredentials the platform credentials used to generate the AC * @param device the device to which the attestation certificate is tied - * @param ldevID whether the certificate is a ldevid + * @param ldevID whether the certificate is a ldevid * @return whether the certificate was saved successfully - * @throws {@link CertificateProcessingException} if error occurs in persisting the Attestation - * Certificate */ public boolean saveAttestationCertificate(final CertificateRepository certificateRepository, final byte[] derEncodedAttestationCertificate, @@ -286,7 +296,7 @@ public class AbstractProcessor { generateCertificate = ldevID ? policySettings.isIssueDevIdCertificate() : policySettings.isIssueAttestationCertificate(); - if (issuedAc != null && issuedAc.size() > 0 + if (issuedAc != null && !issuedAc.isEmpty() && (ldevID ? policySettings.isDevIdExpirationFlag() : policySettings.isGenerateOnExpiration())) { if (issuedAc.get(0).getEndValidity().after(currentDate)) { @@ -322,13 +332,13 @@ public class AbstractProcessor { if (ec == null) { log.warn("Cannot look for platform credential(s). Endorsement credential was null."); } else { - log.debug("Searching for platform credential(s) based on holder serial number: " - + ec.getSerialNumber()); + log.debug("Searching for platform credential(s) based on holder serial number: {}", + ec.getSerialNumber()); credentials = certificateRepository.getByHolderSerialNumber(ec.getSerialNumber()); if (credentials == null || credentials.isEmpty()) { log.warn("No platform credential(s) found"); } else { - log.debug("Platform Credential(s) found: " + credentials.size()); + log.debug("Platform Credential(s) found: {}", credentials.size()); } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimProcessor.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimProcessor.java index cbe87597..1850a1cd 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimProcessor.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/IdentityClaimProcessor.java @@ -20,6 +20,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo; import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo; @@ -156,6 +157,7 @@ public class IdentityClaimProcessor extends AbstractProcessor { } ByteString blobStr = ByteString.copyFrom(new byte[] {}); + if (validationResult == AppraisalStatus.Status.PASS) { RSAPublicKey akPub = ProvisionUtils.parsePublicKey(claim.getAkPublicArea().toByteArray()); byte[] nonce = ProvisionUtils.generateRandomBytes(NONCE_LENGTH); @@ -173,12 +175,14 @@ public class IdentityClaimProcessor extends AbstractProcessor { if (policySettings != null && policySettings.isIgnoreImaEnabled()) { pcrQuoteMask = PCR_QUOTE_MASK.replace("10,", ""); } + // Package response ProvisionerTpm2.IdentityClaimResponse response = ProvisionerTpm2.IdentityClaimResponse.newBuilder() .setCredentialBlob(blobStr).setPcrMask(pcrQuoteMask) .setStatus(ProvisionerTpm2.ResponseStatus.PASS) .build(); + return response.toByteArray(); } else { log.error("Supply chain validation did not succeed. Result is: {}", validationResult); @@ -200,7 +204,8 @@ public class IdentityClaimProcessor extends AbstractProcessor { * @return the {@link AppraisalStatus} of the supply chain validation */ private AppraisalStatus.Status doSupplyChainValidation( - final ProvisionerTpm2.IdentityClaim claim, final PublicKey ekPub) { + final ProvisionerTpm2.IdentityClaim claim, final PublicKey ekPub) throws IOException { + // attempt to find an endorsement credential to validate EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim, ekPub, certificateRepository); @@ -215,6 +220,7 @@ public class IdentityClaimProcessor extends AbstractProcessor { // device.getDeviceInfo().setPaccorOutputString(claim.getPaccorOutput()); handleDeviceComponents(device.getDeviceInfo().getNetworkInfo().getHostname(), claim.getPaccorOutput()); + // There are situations in which the claim is sent with no PCs // or a PC from the tpm which will be deprecated // this is to check what is in the platform object and pull @@ -230,16 +236,18 @@ public class IdentityClaimProcessor extends AbstractProcessor { platformCredentials.addAll(tempList); } + // store component results objects for (PlatformCredential platformCredential : platformCredentials) { List componentResults = componentResultRepository .findByCertificateSerialNumberAndBoardSerialNumber( platformCredential.getSerialNumber().toString(), platformCredential.getPlatformSerial()); + if (componentResults.isEmpty()) { savePlatformComponents(platformCredential); } else { - componentResults.stream().forEach((componentResult) -> { + componentResults.forEach((componentResult) -> { componentResult.restore(); componentResult.resetCreateTime(); componentResultRepository.save(componentResult); @@ -252,13 +260,21 @@ public class IdentityClaimProcessor extends AbstractProcessor { endorsementCredential, platformCredentials, device, componentInfoRepository.findByDeviceName(device.getName())); device.setSummaryId(summary.getId().toString()); + // update the validation result in the device AppraisalStatus.Status validationResult = summary.getOverallValidationResult(); device.setSupplyChainValidationStatus(validationResult); this.deviceRepository.save(device); + return validationResult; } + /** + * Helper method that utilizes the identity claim to produce a device info report. + * + * @param claim identity claim + * @return device info + */ private Device processDeviceInfo(final ProvisionerTpm2.IdentityClaim claim) { DeviceInfoReport deviceInfoReport = null; @@ -275,13 +291,16 @@ public class IdentityClaimProcessor extends AbstractProcessor { } log.info("Processing Device Info Report"); + // store device and device info report. Device device = null; + if (deviceInfoReport.getNetworkInfo() != null && deviceInfoReport.getNetworkInfo().getHostname() != null && !deviceInfoReport.getNetworkInfo().getHostname().isEmpty()) { device = this.deviceRepository.findByName(deviceInfoReport.getNetworkInfo().getHostname()); } + if (device == null) { device = new Device(deviceInfoReport); } @@ -320,6 +339,7 @@ public class IdentityClaimProcessor extends AbstractProcessor { macAddressBytes[i] = hex.byteValue(); } } + NetworkInfo nw = new NetworkInfo(nwProto.getHostname(), ip, macAddressBytes); // Get firmware info @@ -334,16 +354,19 @@ public class IdentityClaimProcessor extends AbstractProcessor { // Get hardware info ProvisionerTpm2.HardwareInfo hwProto = dv.getHw(); + // Make sure chassis info has at least one chassis String firstChassisSerialNumber = DeviceInfoEnums.NOT_SPECIFIED; if (hwProto.getChassisInfoCount() > 0) { firstChassisSerialNumber = hwProto.getChassisInfo(0).getSerialNumber(); } + // Make sure baseboard info has at least one baseboard String firstBaseboardSerialNumber = DeviceInfoEnums.NOT_SPECIFIED; if (hwProto.getBaseboardInfoCount() > 0) { firstBaseboardSerialNumber = hwProto.getBaseboardInfo(0).getSerialNumber(); } + HardwareInfo hw = new HardwareInfo(hwProto.getManufacturer(), hwProto.getProductName(), hwProto.getProductVersion(), hwProto.getSystemSerialNumber(), firstChassisSerialNumber, firstBaseboardSerialNumber); @@ -609,6 +632,14 @@ public class IdentityClaimProcessor extends AbstractProcessor { return dvReport; } + /** + * Helper method that generates digest records using the provided device's manufacturer and model + * information. + * + * @param manufacturer device manufacturer + * @param model device model + * @return boolean that represents that status of the digest records generation + */ private boolean generateDigestRecords(final String manufacturer, final String model) { List rdValues = new LinkedList<>(); SupportReferenceManifest baseSupportRim = null; @@ -620,7 +651,7 @@ public class IdentityClaimProcessor extends AbstractProcessor { .findByManufacturerAndModel(manufacturer, model); Map digestValueMap = new HashMap<>(); - expectedValues.stream().forEach((rdv) -> { + expectedValues.forEach((rdv) -> { digestValueMap.put(rdv.getDigestValue(), rdv); }); @@ -709,35 +740,60 @@ public class IdentityClaimProcessor extends AbstractProcessor { return true; } - private void savePlatformComponents(final Certificate certificate) { + /** + * Helper method that saves the provided platform certificate's components in the database. + * + * @param certificate certificate + */ + private void savePlatformComponents(final Certificate certificate) throws IOException { PlatformCredential platformCredential; + if (certificate instanceof PlatformCredential) { platformCredential = (PlatformCredential) certificate; ComponentResult componentResult; - for (ComponentIdentifier componentIdentifier : platformCredential - .getComponentIdentifiers()) { - componentResult = new ComponentResult(platformCredential.getPlatformSerial(), - platformCredential.getSerialNumber().toString(), - platformCredential.getPlatformChainType(), - componentIdentifier); - componentResult.setFailedValidation(false); - componentResult.setDelta(!platformCredential.isPlatformBase()); - componentResultRepository.save(componentResult); + if (platformCredential.getPlatformConfigurationV1() != null) { + for (ComponentIdentifier componentIdentifier : platformCredential + .getComponentIdentifiers()) { + componentResult = new ComponentResult(platformCredential.getPlatformSerial(), + platformCredential.getSerialNumber().toString(), + platformCredential.getPlatformChainType(), + componentIdentifier); + componentResult.setFailedValidation(false); + componentResult.setDelta(!platformCredential.isPlatformBase()); + componentResultRepository.save(componentResult); + } + } else if (platformCredential.getPlatformConfigurationV2() != null) { + for (ComponentIdentifierV2 componentIdentifierV2 : platformCredential + .getComponentIdentifiersV2()) { + componentResult = new ComponentResult(platformCredential.getPlatformSerial(), + platformCredential.getSerialNumber().toString(), + platformCredential.getPlatformChainType(), + componentIdentifierV2); + componentResult.setFailedValidation(false); + componentResult.setDelta(!platformCredential.isPlatformBase()); + componentResultRepository.save(componentResult); + } } } } - private int handleDeviceComponents(final String hostName, final String paccorString) { - int deviceComponents = 0; + /** + * Helper method that attempts to find all the provided device's components. + * + * @param hostName device's host name + * @param paccorString string representation of the paccor tool output + */ + private void handleDeviceComponents(final String hostName, final String paccorString) { Map componentInfoMap = new HashMap<>(); + try { List componentInfos = SupplyChainCredentialValidator .getComponentInfoFromPaccorOutput(hostName, paccorString); // check the DB for like component infos List dbComponentInfos = this.componentInfoRepository.findByDeviceName(hostName); - dbComponentInfos.stream().forEach((infos) -> { + dbComponentInfos.forEach((infos) -> { componentInfoMap.put(infos.hashCode(), infos); }); @@ -753,7 +809,5 @@ public class IdentityClaimProcessor extends AbstractProcessor { } catch (IOException ioEx) { log.warn("Error parsing paccor string"); } - - return deviceComponents; } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelper.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelper.java index ae22d14a..86a8ea5f 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelper.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelper.java @@ -16,7 +16,6 @@ import java.util.List; public final class CredentialManagementHelper { private CredentialManagementHelper() { - } /** @@ -48,7 +47,7 @@ public final class CredentialManagementHelper { ); } - log.info("Parsing Endorsement Credential of length " + endorsementBytes.length); + log.info("Parsing Endorsement Credential of length {}", endorsementBytes.length); EndorsementCredential endorsementCredential; try { @@ -58,16 +57,18 @@ public final class CredentialManagementHelper { log.error(iae.getMessage()); throw iae; } + int certificateHash = endorsementCredential.getCertificateHash(); EndorsementCredential existingCredential = (EndorsementCredential) certificateRepository .findByCertificateHash(certificateHash); + if (existingCredential == null) { - log.info("No Endorsement Credential found with hash: " + certificateHash); + log.info("No Endorsement Credential found with hash: {}", certificateHash); endorsementCredential.setDeviceName(deviceName); return certificateRepository.save(endorsementCredential); } else if (existingCredential.isArchived()) { - // if the EK is stored in the DB and it's archived, unarchive. - log.info("Unarchiving credential"); + // if the EK is stored in the DB and it's archived, un-archive it. + log.info("Un-archiving endorsement credential"); existingCredential.restore(); existingCredential.resetCreateTime(); certificateRepository.save(existingCredential); @@ -89,28 +90,37 @@ public final class CredentialManagementHelper { final byte[] platformBytes, final String deviceName) { if (certificateRepository == null) { + log.error("The provided certificate repository is null."); throw new IllegalArgumentException("null certificate manager"); } if (platformBytes == null) { + log.error("The provided platform credential byte array is null."); throw new IllegalArgumentException("null platform credential bytes"); } if (platformBytes.length == 0) { + log.error("The provided platform credential byte array is null."); throw new IllegalArgumentException( "zero-length byte array given for platform credential" ); } - log.info("Parsing Platform Credential of length " + platformBytes.length); + log.info("Parsing Platform Credential of length {}", platformBytes.length); + try { PlatformCredential platformCredential = PlatformCredential.parseWithPossibleHeader(platformBytes); + if (platformCredential == null) { + log.error("The platform credential that was parsed with the provided" + + "byte array was null"); return null; } + PlatformCredential existingCredential = (PlatformCredential) certificateRepository .findByCertificateHash(platformCredential.getCertificateHash()); + if (existingCredential == null) { if (platformCredential.getPlatformSerial() != null) { List certificates = certificateRepository @@ -121,10 +131,10 @@ public final class CredentialManagementHelper { if (pc.isPlatformBase() && platformCredential.isPlatformBase()) { // found a base in the database associated with // parsed certificate - log.error(String.format("Base certificate stored" + log.error("Base certificate stored" + " in database with same platform" - + "serial number. (%s)", - platformCredential.getPlatformSerial())); + + "serial number. ({})", + platformCredential.getPlatformSerial()); return null; } } @@ -133,8 +143,8 @@ public final class CredentialManagementHelper { platformCredential.setDeviceName(deviceName); return certificateRepository.save(platformCredential); } else if (existingCredential.isArchived()) { - // if the PC is stored in the DB and it's archived, unarchive. - log.info("Unarchiving credential"); + // if the PC is stored in the DB and it's archived, un-archive it. + log.info("Un-archiving platform credential"); existingCredential.restore(); certificateRepository.save(existingCredential); return existingCredential; @@ -142,10 +152,14 @@ public final class CredentialManagementHelper { return existingCredential; } catch (DBManagerException dbEx) { - log.error("Error retrieving or saving platform credential", dbEx); + log.error("Error retrieving or saving platform credential to the database", dbEx); } catch (Exception e) { log.error("Error parsing platform credential", e); } + + log.error("Due to an exception being thrown while " + + " attempting to store platform certificate(s) " + + "this method will return a null platform certificate."); return null; } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java index 61120b1a..3375f175 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/SupplyChainValidationService.java @@ -32,6 +32,7 @@ import org.apache.logging.log4j.Level; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.IOException; import java.security.KeyStore; import java.util.ArrayList; import java.util.HashMap; @@ -108,7 +109,8 @@ public class SupplyChainValidationService { public SupplyChainValidationSummary validateSupplyChain(final EndorsementCredential ec, final List pcs, final Device device, - final List componentInfos) { + final List componentInfos) + throws IOException { boolean acceptExpiredCerts = getPolicySettings().isExpiredCertificateValidationEnabled(); provisionSessionId = UUID.randomUUID(); PlatformCredential baseCredential = null; @@ -153,6 +155,7 @@ public class SupplyChainValidationService { pcErrorMessage = String.format("%s%s%n", pcErrorMessage, platformScv.getMessage()); } + // set the base credential if (pc.isPlatformBase()) { baseCredential = pc; @@ -407,9 +410,9 @@ public class SupplyChainValidationService { } /** - * Helper function to get a fresh load of the default policy from the DB. + * Helper function that retrieves the default policy settings from the database. * - * @return The default Supply Chain Policy + * @return The default Supply Chain Policy Settings */ private PolicySettings getPolicySettings() { PolicySettings defaultSettings = this.policyRepository.findByName("Default"); diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationService.java index 76efb8df..26ceb8f8 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationService.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationService.java @@ -98,9 +98,10 @@ public final class ValidationService { = SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL; if (platformCredential == null) { - log.error("No platform credential to validate"); + log.error("No platform credential to validate while evaluating platform credential status"); return buildValidationRecord(validationType, - AppraisalStatus.Status.FAIL, "Empty Platform credential", null, Level.ERROR); + AppraisalStatus.Status.FAIL, "Empty Platform credential", null, + Level.ERROR); } log.info("Validating Platform Credential"); @@ -139,12 +140,13 @@ public final class ValidationService { final ComponentResultRepository componentResultRepository, final ComponentAttributeRepository componentAttributeRepository, final List componentInfos, - final UUID provisionSessionId, final boolean ignoreRevisionAttribute) { + final UUID provisionSessionId, final boolean ignoreRevisionAttribute) throws IOException { final SupplyChainValidation.ValidationType validationType = SupplyChainValidation.ValidationType.PLATFORM_CREDENTIAL_ATTRIBUTES; if (platformCredential == null) { - log.error("No platform credential to validate"); + log.error("No platform credential to validate while evaluating platform credential attributes " + + "status"); return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL, "Platform credential is missing", null, Level.ERROR); diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/AcaPciIds.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/AcaPciIds.java index 73e90f12..777cfe26 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/AcaPciIds.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/AcaPciIds.java @@ -110,9 +110,9 @@ public final class AcaPciIds { component.getComponentRevision(), component.getComponentManufacturerId(), component.getFieldReplaceable(), - component.getComponentAddress(), - component.getCertificateIdentifier(), - component.getComponentPlatformUri(), + component.getComponentAddresses(), + component.getComponentPlatformCert(), + component.getComponentPlatformCertUri(), component.getAttributeStatus()); } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CertificateAttributeScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CertificateAttributeScvValidator.java index af9464ca..7604a544 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CertificateAttributeScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CertificateAttributeScvValidator.java @@ -6,6 +6,7 @@ import hirs.attestationca.persist.entity.userdefined.SupplyChainValidation; import hirs.attestationca.persist.entity.userdefined.certificate.ComponentResult; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentAttributeResult; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentClass; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.AttributeStatus; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; @@ -23,6 +24,7 @@ import org.apache.logging.log4j.util.Strings; import org.bouncycastle.asn1.ASN1UTF8String; import org.bouncycastle.asn1.DERUTF8String; +import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -80,8 +82,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid deviceBaseboardSerialNumber = null; } else { deviceInfoSerialNumbers.put("board serial number", deviceBaseboardSerialNumber); - log.info("Using device board serial number for validation: " - + deviceBaseboardSerialNumber); + log.info("Using device board serial number for validation: {}", deviceBaseboardSerialNumber); } if (StringUtils.isEmpty(deviceChassisSerialNumber) @@ -89,16 +90,15 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid log.error("Failed to retrieve device chassis serial number"); } else { deviceInfoSerialNumbers.put("chassis serial number", deviceChassisSerialNumber); - log.info("Using device chassis serial number for validation: " - + deviceChassisSerialNumber); + log.info("Using device chassis serial number for validation: {}", deviceChassisSerialNumber); } + if (StringUtils.isEmpty(deviceSystemSerialNumber) || DeviceInfoEnums.NOT_SPECIFIED.equalsIgnoreCase(deviceSystemSerialNumber)) { log.error("Failed to retrieve device system serial number"); } else { deviceInfoSerialNumbers.put("system serial number", deviceSystemSerialNumber); - log.info("Using device system serial number for validation: " - + deviceSystemSerialNumber); + log.info("Using device system serial number for validation: {}", deviceSystemSerialNumber); } AppraisalStatus status; @@ -169,7 +169,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid final ComponentResultRepository componentResultRepository, final ComponentAttributeRepository componentAttributeRepository, final List componentInfos, - final UUID provisionSessionId, final boolean ignoreRevisionAttribute) { + final UUID provisionSessionId, final boolean ignoreRevisionAttribute) throws IOException { boolean passesValidation = true; StringBuilder resultMessage = new StringBuilder(); HardwareInfo hardwareInfo = deviceInfoReport.getHardwareInfo(); @@ -233,29 +233,132 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid passesValidation &= fieldValidation; - // Retrieve the list of all components from the Platform Credential - List allPcComponents - = new ArrayList<>(platformCredential.getComponentIdentifiers()); + if (platformCredential.getPlatformConfigurationV1() != null) { - // All components listed in the Platform Credential must have a manufacturer and model - for (ComponentIdentifier pcComponent : allPcComponents) { - fieldValidation = !hasEmptyValueForRequiredField("componentManufacturer", - pcComponent.getComponentManufacturer()); + // Retrieve the list of all version 1 component identifiers from the Platform Credential + List allPcComponents + = new ArrayList<>(platformCredential.getComponentIdentifiers()); - if (!fieldValidation) { - resultMessage.append("Component manufacturer is empty\n"); + // All V1 components listed in the Platform Credential must have a manufacturer and model + for (ComponentIdentifier pcComponent : allPcComponents) { + + fieldValidation = !isRequiredASN1StringFieldBlank("componentManufacturer", + pcComponent.getComponentManufacturer()); + + if (!fieldValidation) { + resultMessage.append("Component manufacturer is empty\n"); + } + + passesValidation &= fieldValidation; + + fieldValidation = !isRequiredASN1StringFieldBlank("componentModel", + pcComponent.getComponentModel()); + + if (!fieldValidation) { + resultMessage.append("Component model is empty\n"); + } + + passesValidation &= fieldValidation; } - passesValidation &= fieldValidation; + } else if (platformCredential.getPlatformConfigurationV2() != null) { + // Retrieve the list of all version 2 component identifiers from the Platform Credential + List allV2PcComponents + = new ArrayList<>(platformCredential.getComponentIdentifiersV2()); - fieldValidation = !hasEmptyValueForRequiredField("componentModel", - pcComponent.getComponentModel()); - if (!fieldValidation) { - resultMessage.append("Component model is empty\n"); + // All V2 components listed in the Platform Credential must have a manufacturer and model + for (ComponentIdentifierV2 pcComponent : allV2PcComponents) { + fieldValidation = !isRequiredASN1StringFieldBlank("componentManufacturer", + pcComponent.getComponentManufacturer()); + + if (!fieldValidation) { + resultMessage.append("Component manufacturer is empty\n"); + } + + passesValidation &= fieldValidation; + + fieldValidation = !isRequiredASN1StringFieldBlank("componentModel", + pcComponent.getComponentModel()); + + if (!fieldValidation) { + resultMessage.append("Component model is empty\n"); + } + + passesValidation &= fieldValidation; + + if (pcComponent.getComponentClass() == null) { + passesValidation = false; + } else { + ComponentClass pcComponentClass = pcComponent.getComponentClass(); + + // Component Class Registry Type field + + fieldValidation = !isRequiredStringFieldBlank("registryType", + pcComponentClass.getRegistryType()); + + if (!fieldValidation) { + resultMessage.append("Component class registry type is empty or null\n"); + } + + passesValidation &= fieldValidation; + + // Component Class Component Identifier field + + fieldValidation = !isRequiredStringFieldBlank("componentIdentifier", + pcComponentClass.getComponentIdentifier()); + + if (!fieldValidation) { + resultMessage.append("Component class component identifier is empty or null\n"); + } + + passesValidation &= fieldValidation; + + // Component Class category field + + fieldValidation = !isRequiredStringFieldBlank("category", + pcComponentClass.getCategory()); + + if (!fieldValidation) { + resultMessage.append("Component class category is empty or null\n"); + } + + passesValidation &= fieldValidation; + + // Component Class Category String field + + fieldValidation = !isRequiredStringFieldBlank("categoryStr", + pcComponentClass.getCategoryStr()); + + if (!fieldValidation) { + resultMessage.append("Component class category string is empty or null\n"); + } + + passesValidation &= fieldValidation; + + // Component Class Component String field + + fieldValidation = !isRequiredStringFieldBlank("componentStr", + pcComponentClass.getComponentStr()); + + if (!fieldValidation) { + resultMessage.append("Component class string is empty or null\n"); + } + + passesValidation &= fieldValidation; + + // Component Class Component field + + fieldValidation = !isRequiredStringFieldBlank("component", + pcComponentClass.getComponent()); + + if (!fieldValidation) { + resultMessage.append("Component class component is empty or null\n"); + } + + passesValidation &= fieldValidation; + } } - - passesValidation &= fieldValidation; } // populate componentResults list @@ -263,18 +366,24 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid .findByCertificateSerialNumberAndBoardSerialNumber( platformCredential.getSerialNumber().toString(), platformCredential.getPlatformSerial()); + // first create hash map based on hashCode List remainingComponentResults = checkDeviceHashMap( componentInfos, componentResults); + //this is used to get a unique count List componentIdList = new ArrayList<>(); + int numOfAttributes = 0; + if (!remainingComponentResults.isEmpty()) { List attributeResults = checkComponentClassMap( componentInfos, remainingComponentResults); numOfAttributes = attributeResults.size(); + boolean saveAttributeResult; + for (ComponentAttributeResult componentAttributeResult : attributeResults) { saveAttributeResult = true; if (ignoreRevisionAttribute) { @@ -293,6 +402,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid } StringBuilder additionalInfo = new StringBuilder(); + if (numOfAttributes > 0) { resultMessage.append(String.format("There are %d component(s) not matched%n " + "with %d total attributes mismatched.", @@ -435,7 +545,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid for (ComponentInfo cInfo : allDeviceInfoComponents) { for (ComponentIdentifier cId : fullDeltaChainComponents) { ciV2 = (ComponentIdentifierV2) cId; - if (cInfo.getComponentClass().contains( + if (cInfo.getComponentClassValue().contains( ciV2.getComponentClass().getComponentIdentifier()) && isMatch(cId, cInfo)) { subCompIdList.remove(cId); @@ -455,7 +565,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid if (ci.isVersion2() && PciIds.DB.isReady()) { ci = AcaPciIds.translate((ComponentIdentifierV2) ci); } - log.error("Unmatched component: " + ci); + log.error("Unmatched component: {}", ci); fullDeltaChainComponents.add(ci); invalidPcIds.append(String.format( "Manufacturer=%s, Model=%s, Serial=%s, Revision=%s;%n", @@ -513,25 +623,34 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid log.info("Validating the following Platform Cert components..."); pcComponents.forEach(component -> log.info(component.toString())); + log.info("...against the the following DeviceInfoReport components:"); allDeviceInfoComponents.forEach(component -> log.info(component.toString())); + Set manufacturerSet = new HashSet<>(); + // create a set of component manufacturers pcComponents.forEach(pcComp -> manufacturerSet.add(pcComp.getComponentManufacturer())); // Create a list for unmatched components across all manufacturers to display at the end. List pcUnmatchedComponents = new ArrayList<>(); for (ASN1UTF8String derUtf8Manufacturer : manufacturerSet) { + + // look for all the component identifiers whose manufacturer matches that of the current + // manufacturer List pcComponentsFromManufacturer = pcComponents.stream().filter(compIdentifier -> compIdentifier.getComponentManufacturer().equals(derUtf8Manufacturer)) .collect(Collectors.toList()); - String pcManufacturer = derUtf8Manufacturer.getString(); + // look for all the component infos whose manufacturer matches that of the current + // manufacturer + String currentPCManufacturer = derUtf8Manufacturer.getString(); List deviceInfoComponentsFromManufacturer = allDeviceInfoComponents.stream().filter(componentInfo - -> componentInfo.getComponentManufacturer().equals(pcManufacturer)) + -> componentInfo.getComponentManufacturer().equals(currentPCManufacturer)) .collect(Collectors.toList()); + // For each component listed in the platform credential from this manufacturer // find the ones that specify a serial number so we can match the most specific ones // first. @@ -539,7 +658,8 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid = pcComponentsFromManufacturer.stream().filter(compIdentifier -> compIdentifier.getComponentSerial() != null && StringUtils.isNotEmpty(compIdentifier.getComponentSerial().getString())) - .collect(Collectors.toList()); + .toList(); + // Now match up the components from the device info that are from the same // manufacturer and have a serial number. As matches are found, remove them from // both lists. @@ -560,6 +680,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid } } } + // For each component listed in the platform credential from this manufacturer // find the ones that specify value for the revision field so we can match the most // specific ones first. @@ -567,7 +688,8 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid = pcComponentsFromManufacturer.stream().filter(compIdentifier -> compIdentifier.getComponentRevision() != null && StringUtils.isNotEmpty(compIdentifier.getComponentRevision().getString())) - .collect(Collectors.toList()); + .toList(); + // Now match up the components from the device info that are from the same // manufacturer and specify a value for the revision field. As matches are found, // remove them from both lists. @@ -608,8 +730,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid if (!pcUnmatchedComponents.isEmpty()) { untrimmedPcComponents.clear(); StringBuilder sb = new StringBuilder(); - log.error(String.format("Platform Credential contained %d unmatched components:", - pcUnmatchedComponents.size())); + log.error("Platform Credential contained {} unmatched components:", pcUnmatchedComponents.size()); int unmatchedComponentCounter = 1; for (ComponentIdentifier unmatchedComponent : pcUnmatchedComponents) { @@ -617,8 +738,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid unmatchedComponent = AcaPciIds.translate((ComponentIdentifierV2) unmatchedComponent); } - log.error("Unmatched component " + unmatchedComponentCounter++ + ": " - + unmatchedComponent); + log.error("Unmatched component {}: {}", unmatchedComponentCounter++, unmatchedComponent); sb.append(String.format("Manufacturer=%s, Model=%s, Serial=%s, Revision=%s;%n", unmatchedComponent.getComponentManufacturer(), unmatchedComponent.getComponentModel(), @@ -670,7 +790,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid private static boolean isMatchOrEmptyInPlatformCert( final String evidenceFromDevice, final ASN1UTF8String valueInPlatformCert) { - if (valueInPlatformCert == null || StringUtils.isEmpty(valueInPlatformCert.getString())) { + if (StringUtils.isBlank(valueInPlatformCert.getString())) { return true; } return valueInPlatformCert.getString().equals(evidenceFromDevice); @@ -756,7 +876,7 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid final String platformCredentialFieldName, final String platformCredentialFieldValue, final String otherValue) { - if (hasEmptyValueForRequiredField(platformCredentialFieldName, + if (isRequiredStringFieldBlank(platformCredentialFieldName, platformCredentialFieldValue)) { return false; } @@ -794,11 +914,10 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid * @param fieldValue value of the field * @return true if fieldValue is null or empty; false otherwise */ - private static boolean hasEmptyValueForRequiredField(final String description, - final String fieldValue) { - if (StringUtils.isEmpty(fieldValue)) { - log.error("Required field was empty or null in Platform Credential: " - + description); + private static boolean isRequiredStringFieldBlank(final String description, + final String fieldValue) { + if (StringUtils.isBlank(fieldValue)) { + log.error("Required string field was empty or null in Platform Credential: {}", description); return true; } return false; @@ -829,15 +948,15 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid String trimmedOtherValue = otherValue.trim(); if (!trimmedFieldValue.equals(trimmedOtherValue)) { - log.debug(String.format("%s field in Platform Credential (%s) does not match " - + "a related field in the DeviceInfoReport (%s)", - platformCredentialFieldName, trimmedFieldValue, trimmedOtherValue)); + log.debug("{} field in Platform Credential ({}) does not match " + + "a related field in the DeviceInfoReport ({})", + platformCredentialFieldName, trimmedFieldValue, trimmedOtherValue); return false; } - log.debug(String.format("%s field in Platform Credential matches " - + "a related field in the DeviceInfoReport (%s)", - platformCredentialFieldName, trimmedFieldValue) + log.debug("{} field in Platform Credential matches " + + "a related field in the DeviceInfoReport {}", + platformCredentialFieldName, trimmedFieldValue ); return true; @@ -850,11 +969,10 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid * @param fieldValue value of the field * @return true if fieldValue is null or empty; false otherwise */ - private static boolean hasEmptyValueForRequiredField(final String description, - final ASN1UTF8String fieldValue) { - if (fieldValue == null || StringUtils.isEmpty(fieldValue.getString().trim())) { - log.error("Required field was empty or null in Platform Credential: " - + description); + private static boolean isRequiredASN1StringFieldBlank(final String description, + final ASN1UTF8String fieldValue) { + if (fieldValue == null || StringUtils.isBlank(fieldValue.getString().trim())) { + log.error("Required ASN1 string field was empty or null in Platform Credential: {}", description); return true; } return false; @@ -871,16 +989,17 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid final List componentInfos, final List compiledComponentList) { Map> deviceHashMap = new HashMap<>(); - componentInfos.stream().forEach((componentInfo) -> { - List innerList; + + componentInfos.forEach((componentInfo) -> { + List innerList = new ArrayList<>(); Integer compInfoHash = componentInfo.hashCommonElements(); + if (deviceHashMap.containsKey(compInfoHash)) { innerList = deviceHashMap.get(compInfoHash); - innerList.add(componentInfo); - } else { - innerList = new ArrayList<>(0); - innerList.add(componentInfo); } + + innerList.add(componentInfo); + deviceHashMap.put(compInfoHash, innerList); }); @@ -910,23 +1029,37 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid // continue down the options, move to a different method. // create component class mapping to component info Map> componentDeviceMap = new HashMap<>(); - componentInfos.stream().forEach((componentInfo) -> { - List innerList; - String componentClass = componentInfo.getComponentClass(); + + componentInfos.forEach((componentInfo) -> { + List innerList = new ArrayList<>(); + String componentClass = componentInfo.getComponentClassValue(); + if (componentDeviceMap.containsKey(componentClass)) { innerList = componentDeviceMap.get(componentClass); - innerList.add(componentInfo); - } else { - innerList = new ArrayList<>(0); - innerList.add(componentInfo); } + + innerList.add(componentInfo); + componentDeviceMap.put(componentClass, innerList); }); List componentClassInfo; List attributeResults = new ArrayList<>(); + for (ComponentResult componentResult : remainingComponentResults) { + componentClassInfo = componentDeviceMap.get(componentResult.getComponentClassValue()); + + if (componentClassInfo == null) { + log.error("The retrieved list of component class info is null. The null list" + + "is associated with the component result's component class value of {}", + componentResult.getComponentClassValue()); + + //move on to the next iteration since there is nothing we can do with the null + // component class info + continue; + } + if (componentClassInfo.size() == 1) { attributeResults.addAll(generateComponentAttributeResults( componentClassInfo.get(0), componentResult)); @@ -1000,11 +1133,13 @@ public class CertificateAttributeScvValidator extends SupplyChainCredentialValid private static List findMismatchedValues( final List componentClassInfo, final ComponentResult componentResult) { + // this list only has those of the same class type Map componentSerialMap = new HashMap<>(); - componentClassInfo.stream().forEach((componentInfo) -> { + componentClassInfo.forEach((componentInfo) -> { componentSerialMap.put(componentInfo.getComponentSerial(), componentInfo); }); + // see if the serial exists ComponentInfo componentInfo = componentSerialMap.get(componentResult.getSerialNumber()); diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java index 722f9b48..1913ccd5 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/CredentialValidator.java @@ -35,7 +35,7 @@ public class CredentialValidator extends SupplyChainCredentialValidator { * * @param ec the endorsement credential to verify. * @param trustStore trust store holding trusted certificates. - * @param acceptExpired whether or not to accept expired and not yet valid certificates + * @param acceptExpired whether to accept expired and not yet valid certificates * as valid. * @return the result of the validation. */ @@ -100,7 +100,7 @@ public class CredentialValidator extends SupplyChainCredentialValidator { * * @param pc The platform credential to verify. * @param trustStore trust store holding trusted certificates. - * @param acceptExpired whether or not to accept expired certificates as valid. + * @param acceptExpired whether to accept expired certificates as valid. * @return The result of the validation. */ public static AppraisalStatus validatePlatformCredential(final PlatformCredential pc, @@ -183,21 +183,24 @@ public class CredentialValidator extends SupplyChainCredentialValidator { final ComponentResultRepository componentResultRepository, final ComponentAttributeRepository componentAttributeRepository, final List componentInfos, - final UUID provisionSessionId, final boolean ignoreRevisionAttribute) { + final UUID provisionSessionId, final boolean ignoreRevisionAttribute) throws IOException { final String baseErrorMessage = "Can't validate platform credential attributes without "; String message; if (platformCredential == null) { message = baseErrorMessage + "a platform credential"; return new AppraisalStatus(FAIL, message); } + if (deviceInfoReport == null) { message = baseErrorMessage + "a device info report"; return new AppraisalStatus(FAIL, message); } + if (endorsementCredential == null) { message = baseErrorMessage + "an endorsement credential"; return new AppraisalStatus(FAIL, message); } + if (componentInfos.isEmpty()) { message = baseErrorMessage + "a list of device components"; return new AppraisalStatus(FAIL, message); diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java index 914ac968..2e36dc09 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidator.java @@ -93,7 +93,9 @@ public class SupplyChainCredentialValidator { throw new SupplyChainValidatorException("Truststore is empty"); } } catch (KeyStoreException ksEx) { - log.error("Error accessing trust store: " + ksEx.getMessage()); + log.error( + "Error accessing trust store while trying to verify the X509 Attribute" + + " Certificate Holder: {}", ksEx.getMessage()); } try { @@ -134,7 +136,8 @@ public class SupplyChainCredentialValidator { throw new SupplyChainValidatorException("Truststore is empty"); } } catch (KeyStoreException ksEx) { - log.error("Error accessing trust store: " + ksEx.getMessage()); + log.error("Error accessing trust store while trying to verify the X509 Certificate: {}", + ksEx.getMessage()); } try { @@ -147,8 +150,9 @@ public class SupplyChainCredentialValidator { return validateCertChain(cert, trustedCerts).isEmpty(); } catch (KeyStoreException ksEx) { - log.error("Error accessing keystore", ksEx); - throw new SupplyChainValidatorException("Error with the trust store", ksEx); + log.error("Error accessing keystore while trying to verify the X509 Certificate", ksEx); + throw new SupplyChainValidatorException( + "Error accessing keystore while trying to verify the X509 Certificate", ksEx); } } @@ -191,7 +195,7 @@ public class SupplyChainCredentialValidator { if (issuerMatchesSubject && signatureMatchesPublicKey) { if (isSelfSigned(trustedCert)) { - log.info("CA Root found."); + log.info("CA Root found while validating the X509 Attribute Certificate Holder."); return ""; } else { foundRootOfCertChain = intCAError; @@ -244,7 +248,7 @@ public class SupplyChainCredentialValidator { trustedCert); if (issuerMatchesSubject && signatureMatchesPublicKey) { if (isSelfSigned(trustedCert)) { - log.info("CA Root found."); + log.info("CA Root found while validating X509 Certificate."); return ""; } else { foundRootOfCertChain = intCAError; @@ -270,7 +274,7 @@ public class SupplyChainCredentialValidator { * Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects. * * @param hostName the host machine associated with the component - * @param paccorOutput the output from PACCOR's allcomoponents.sh + * @param paccorOutput the output from PACCOR's allcomponents.sh * @return a list of ComponentInfo objects built from paccorOutput * @throws java.io.IOException if something goes wrong parsing the JSON */ @@ -296,17 +300,23 @@ public class SupplyChainCredentialValidator { getJSONNodeValueAsText(next, "REVISION"))); } else { // version 2 - String componentClass = StringUtils.EMPTY; + String componentClassValue = StringUtils.EMPTY; + String componentClassRegistry = StringUtils.EMPTY; + for (JsonNode subNode : compClassNodes) { - componentClass = getJSONNodeValueAsText(subNode, + componentClassValue = getJSONNodeValueAsText(subNode, "COMPONENTCLASSVALUE"); + componentClassRegistry = getJSONNodeValueAsText(subNode, + "COMPONENTCLASSREGISTRY"); } + componentInfoList.add(new ComponentInfo(hostName, getJSONNodeValueAsText(next, "MANUFACTURER"), getJSONNodeValueAsText(next, "MODEL"), getJSONNodeValueAsText(next, "SERIAL"), getJSONNodeValueAsText(next, "REVISION"), - componentClass)); + componentClassValue, + componentClassRegistry)); } } } @@ -314,6 +324,13 @@ public class SupplyChainCredentialValidator { return componentInfoList; } + /** + * Helper method that attempts to retrieve the value as text from the provided Json Node. + * + * @param node json node + * @param fieldName field name + * @return string json node value + */ private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) { if (node.hasNonNull(fieldName)) { return node.findValue(fieldName).textValue(); @@ -398,8 +415,7 @@ public class SupplyChainCredentialValidator { } catch (NoSuchProviderException e) { log.info("Incorrect provider for cert signature validation"); } catch (SignatureException e) { - log.info(String.format("%s.verify(%s)", cert.getSubjectX500Principal(), - signingCert.getSubjectX500Principal())); + log.info("{}.verify({})", cert.getSubjectX500Principal(), signingCert.getSubjectX500Principal()); } return false; @@ -444,8 +460,7 @@ public class SupplyChainCredentialValidator { return cert.isSignatureValid(contentVerifierProvider); } catch (OperatorCreationException | CertException e) { log.info("Exception thrown while verifying certificate", e); - log.info(String.format("%s.isSignatureValid(%s)", cert.getSerialNumber(), - signingKey.getFormat())); + log.info("{}.isSignatureValid({})", cert.getSerialNumber(), signingKey.getFormat()); return false; } } diff --git a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredentialTest.java b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredentialTest.java index 355fa903..6ab46e53 100644 --- a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredentialTest.java +++ b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/PlatformCredentialTest.java @@ -3,10 +3,11 @@ package hirs.attestationca.persist.entity.userdefined.certificate; import hirs.attestationca.persist.entity.userdefined.AbstractUserdefinedEntityTest; import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; -import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfigurationV1; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformProperty; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.TBBSecurityAssertion; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2; import org.apache.commons.codec.binary.Hex; import org.bouncycastle.util.encoders.Base64; @@ -439,10 +440,10 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV1 platformConfigV1 = platformCert.getPlatformConfigurationV1(); //Check component identifier - List allComponents = platformConfig.getComponentIdentifier(); + List allComponents = platformConfigV1.getComponentIdentifiers(); if (allComponents.isEmpty()) { Assertions.fail("Component Identifier is empty."); } @@ -472,14 +473,14 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { component = allComponents.get(component5Position); Assertions.assertEquals("Ethernet Connection I219-LM", component.getComponentModel() .getString()); - Assertions.assertEquals("8c:0f:6f:72:c6:c5", component.getComponentAddress().get(0) + Assertions.assertEquals("8c:0f:6f:72:c6:c5", component.getComponentAddresses().get(0) .getAddressValue() .getString()); - Assertions.assertEquals("ethernet mac", component.getComponentAddress().get(0) + Assertions.assertEquals("ethernet mac", component.getComponentAddresses().get(0) .getAddressTypeValue()); //Check Platform Properties - List platformProperties = platformConfig.getPlatformProperties(); + List platformProperties = platformConfigV1.getPlatformProperties(); if (platformProperties.isEmpty()) { Assertions.fail("Platform Properties is empty."); } @@ -499,7 +500,7 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Assertions.assertEquals("true", property.getPropertyValue().getString()); //Check Platform Properties URI - URIReference platformPropertyUri = platformConfig.getPlatformPropertiesUri(); + URIReference platformPropertyUri = platformConfigV1.getPlatformPropertiesUri(); Assertions.assertNotNull(platformPropertyUri); Assertions.assertEquals("https://www.intel.com/platformproperties.xml", @@ -522,13 +523,13 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV1 platformConfigV1 = platformCert.getPlatformConfigurationV1(); //Check component identifier - List allComponents = platformConfig.getComponentIdentifier(); + List allComponents = platformConfigV1.getComponentIdentifiers(); Assertions.assertTrue(allComponents.isEmpty()); - List platformProperties = platformConfig.getPlatformProperties(); + List platformProperties = platformConfigV1.getPlatformProperties(); if (platformProperties.isEmpty()) { Assertions.fail("Platform Properties is empty."); } @@ -560,10 +561,10 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV1 platformConfigV1 = platformCert.getPlatformConfigurationV1(); //Check component identifier - List allComponents = platformConfig.getComponentIdentifier(); + List allComponents = platformConfigV1.getComponentIdentifiers(); if (allComponents.isEmpty()) { Assertions.fail("Component Identifier is empty."); } @@ -589,7 +590,7 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { .getString()); //Check Platform Properties - List platformProperties = platformConfig.getPlatformProperties(); + List platformProperties = platformConfigV1.getPlatformProperties(); if (platformProperties.isEmpty()) { Assertions.fail("Platform Properties is empty."); } @@ -597,7 +598,7 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Assertions.assertEquals(platformProperties.size(), 2); //Check Platform Properties URI - URIReference platformPropertyUri = platformConfig.getPlatformPropertiesUri(); + URIReference platformPropertyUri = platformConfigV1.getPlatformPropertiesUri(); Assertions.assertNotNull(platformPropertyUri); Assertions.assertEquals("https://www.intel.com/platformproperties.xml", @@ -629,10 +630,10 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV1 platformConfigV1 = platformCert.getPlatformConfigurationV1(); //Check component identifier - List allComponents = platformConfig.getComponentIdentifier(); + List allComponents = platformConfigV1.getComponentIdentifiers(); if (allComponents.isEmpty()) { Assertions.fail("Component Identifier is empty."); } @@ -651,15 +652,15 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { //Check component #7 final int component7Position = 6; component = allComponents.get(component7Position); - Assertions.assertTrue(component.getComponentAddress().size() > 0); - Assertions.assertEquals("8c:0f:6f:72:c6:c5", component.getComponentAddress().get(0) + Assertions.assertFalse(component.getComponentAddresses().isEmpty()); + Assertions.assertEquals("8c:0f:6f:72:c6:c5", component.getComponentAddresses().get(0) .getAddressValue() .getString()); - Assertions.assertEquals("ethernet mac", component.getComponentAddress().get(0) + Assertions.assertEquals("ethernet mac", component.getComponentAddresses().get(0) .getAddressTypeValue()); //Check Platform Properties - List platformProperties = platformConfig.getPlatformProperties(); + List platformProperties = platformConfigV1.getPlatformProperties(); if (platformProperties.isEmpty()) { Assertions.fail("Platform Properties is empty."); } @@ -667,7 +668,7 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Assertions.assertEquals(platformProperties.size(), 2); //Check Platform Properties URI - URIReference platformPropertyUri = platformConfig.getPlatformPropertiesUri(); + URIReference platformPropertyUri = platformConfigV1.getPlatformPropertiesUri(); Assertions.assertNotNull(platformPropertyUri); Assertions.assertEquals("https://www.intel.com/platformproperties.xml", @@ -700,17 +701,17 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV2 platformConfigV2 = platformCert.getPlatformConfigurationV2(); //Check component identifier - List allComponents = platformConfig.getComponentIdentifier(); + List allComponents = platformConfigV2.getComponentIdentifiers(); Assertions.assertFalse(allComponents.isEmpty()); final int component6Position = 5; - ComponentIdentifier component = allComponents.get(component6Position); + ComponentIdentifierV2 component = allComponents.get(component6Position); Assertions.assertTrue(component.isVersion2()); - List platformProperties = platformConfig.getPlatformProperties(); + List platformProperties = platformConfigV2.getPlatformProperties(); if (platformProperties.isEmpty()) { Assertions.fail("Platform Properties is empty."); } @@ -749,15 +750,15 @@ public class PlatformCredentialTest extends AbstractUserdefinedEntityTest { Path certPath = Paths.get(resource.toURI()); PlatformCredential platformCert = new PlatformCredential(certPath); - PlatformConfiguration platformConfig = platformCert.getPlatformConfiguration(); + PlatformConfigurationV2 platformConfigV2 = platformCert.getPlatformConfigurationV2(); - Assertions.assertInstanceOf(PlatformConfigurationV2.class, platformConfig); - Assertions.assertEquals(platformConfig.getPlatformPropertiesUri() + Assertions.assertInstanceOf(PlatformConfigurationV2.class, platformConfigV2); + Assertions.assertEquals(platformConfigV2.getPlatformPropertiesUri() .getUniformResourceIdentifier().toString(), "https://www.intel.com/platformproperties.xml"); -// Assertions.assertNotNull(platformConfig.getComponentIdentifierUri()); +// Assertions.assertNotNull(platformConfigV1.getComponentIdentifiersUri()); -// Assertions.assertEquals(platformConfig.getComponentIdentifierUri() +// Assertions.assertEquals(platformConfigV1.getComponentIdentifiersUri() // .getUniformResourceIdentifier().toString(), // "https://www.intel.com/platformidentifiers.xml"); diff --git a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClassTest.java b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClassTest.java index b148ac38..92653f95 100644 --- a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClassTest.java +++ b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/entity/userdefined/certificate/attributes/ComponentClassTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import java.net.URISyntaxException; import java.nio.file.Paths; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -16,292 +17,313 @@ public class ComponentClassTest { private static final String JSON_FILE = "/config/component-class.json"; /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNoneUNK() throws URISyntaxException { - String componentIdentifier = "00000001"; + final String componentIdentifier = "00000001"; ComponentClass instance = new ComponentClass("TCG", - Paths.get(this.getClass().getResource(JSON_FILE).toURI()), + Paths.get(Objects.requireNonNull(this.getClass().getResource(JSON_FILE)).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNoneOther() throws URISyntaxException { - String componentIdentifier = "00000000"; + final String componentIdentifier = "00000000"; ComponentClass instance = new ComponentClass("TCG", Paths.get(this.getClass() .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentBlank() throws URISyntaxException { - String componentIdentifier = ""; + final String componentIdentifier = ""; ComponentClass instance = new ComponentClass(Paths.get(this.getClass() .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNFEx() throws URISyntaxException { - String componentIdentifier = "99999999"; + final String componentIdentifier = "99999999"; ComponentClass instance = new ComponentClass(Paths.get(this.getClass() .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNull() throws URISyntaxException { - String componentIdentifier = null; + final String componentIdentifier = null; ComponentClass instance = new ComponentClass(Paths.get(this.getClass() .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class where the + * registry type is of type TCG. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQueryTCG() throws URISyntaxException { - String componentIdentifier = "0x00040002"; + final String componentIdentifier = "0x00040002"; ComponentClass instance = new ComponentClass(Paths.get(this.getClass() .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("SAS Bridgeboard", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class where the + * registry type is of type SMBIOS. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQuerySMBIOS() throws URISyntaxException { - String componentIdentifier = "0x00040003"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.3", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040003"; + ComponentClass instance = new ComponentClass("2.23.133.18.3.3", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); + final String resultRegistry = instance.getRegistryType(); + + assertEquals("SMBIOS", resultRegistry); assertEquals("Central Processor", resultComponent); assertEquals("Processor", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Test of getComponent method, of class ComponentClass where the + * registry type is of type PCIE. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test - public void testGetComponentStandardQueryIntTCG() throws URISyntaxException { - String componentIdentifier = "0x00040002"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); - assertEquals("SAS Bridgeboard", resultComponent); - assertEquals("Modules", resultCategory); + public void testGetComponentStandardQueryPCIE() throws URISyntaxException { + final String componentIdentifier = "0x00080004"; // TODO placeholder for now + ComponentClass instance = new ComponentClass("2.23.133.18.3.4", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultRegistry = instance.getRegistryType(); + + assertEquals("PCIE", resultRegistry); + + //TODO Once the component-class.json file is updated to reflect the two new component + // registries, we will then write tests that test the component class' category/component + // properties. } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class where the + * registry type is of type STORAGE. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test - public void testGetComponentStandardQueryIntSMBIOS() throws URISyntaxException { - String componentIdentifier = "0x00040003"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.3", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); - assertEquals("Central Processor", resultComponent); - assertEquals("Processor", resultCategory); + public void testGetComponentStandardQuerySTORAGE() throws URISyntaxException { + final String componentIdentifier = "0x00080004"; // TODO placeholder for now + ComponentClass instance = new ComponentClass("2.23.133.18.3.5", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultRegistry = instance.getRegistryType(); + + assertEquals("STORAGE", resultRegistry); + + //TODO Once the component-class.json file is updated to reflect the two new component + // registries, we will then write tests that test the component class' category/component + // properties. + } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQueryIntOther() throws URISyntaxException { - String componentIdentifier = "0x00040000"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040000"; + ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Other", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQueryIntUnk() throws URISyntaxException { - String componentIdentifier = "0x00040001"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040001"; + ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQuery2() throws URISyntaxException { - String componentIdentifier = "0x00060015"; - ComponentClass instance = new ComponentClass(Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00060015"; + ComponentClass instance = new ComponentClass(Paths.get(Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("DDR3 Memory", resultComponent); assertEquals("Memory", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentStandardQueryUNK() throws URISyntaxException { - String componentIdentifier = "0x00060001"; - ComponentClass instance = new ComponentClass(Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00060001"; + ComponentClass instance = new ComponentClass(Paths.get(Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("Memory", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNonStandardQuery() throws URISyntaxException { - String componentIdentifier = "0x00040002"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040002"; + ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("SAS Bridgeboard", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNonStandardQuery2() throws URISyntaxException { - String componentIdentifier = "0x00040002"; - ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040002"; + ComponentClass instance = new ComponentClass("2.23.133.18.3.1", Paths.get( + Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("SAS Bridgeboard", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNonExistentValue() throws URISyntaxException { - String componentIdentifier = "0x00040014"; - ComponentClass instance = new ComponentClass(Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x00040014"; + ComponentClass instance = new ComponentClass(Paths.get(Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertNotNull(resultComponent); assertEquals("Unknown", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNonExistentValue2() throws URISyntaxException { - String componentIdentifier = "0x0004FF14"; - ComponentClass instance = new ComponentClass(Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x0004FF14"; + ComponentClass instance = new ComponentClass(Paths.get(Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertNotNull(resultComponent); assertEquals("Unknown", resultComponent); assertEquals("Modules", resultCategory); } /** - * Test of getComponent method, of class ComponentClass. + * Tests the getComponent method from the ComponentClass class. * * @throws URISyntaxException if there is a problem constructing the URI */ @Test public void testGetComponentNonExistentCategory() throws URISyntaxException { - String componentIdentifier = "0x0015FF14"; - ComponentClass instance = new ComponentClass(Paths.get(this.getClass() - .getResource(JSON_FILE).toURI()), componentIdentifier); - String resultCategory = instance.getCategoryStr(); - String resultComponent = instance.getComponentStr(); + final String componentIdentifier = "0x0015FF14"; + ComponentClass instance = new ComponentClass(Paths.get(Objects.requireNonNull(this.getClass() + .getResource(JSON_FILE)).toURI()), componentIdentifier); + final String resultCategory = instance.getCategoryStr(); + final String resultComponent = instance.getComponentStr(); assertEquals("Unknown", resultComponent); assertEquals("None", resultCategory); } diff --git a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidatorTest.java b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidatorTest.java index 7384e4b5..83feb030 100644 --- a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidatorTest.java +++ b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/validation/SupplyChainCredentialValidatorTest.java @@ -1,17 +1,25 @@ package hirs.attestationca.persist.validation; +import hirs.attestationca.persist.entity.manager.ComponentAttributeRepository; +import hirs.attestationca.persist.entity.manager.ComponentResultRepository; import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentClass; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfigurationV1; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.URIReference; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.AttributeStatus; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.CertificateIdentifier; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2; import hirs.attestationca.persist.entity.userdefined.info.ComponentInfo; import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo; import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo; import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo; import hirs.attestationca.persist.entity.userdefined.info.OSInfo; import hirs.attestationca.persist.entity.userdefined.info.TPMInfo; -import hirs.attestationca.persist.entity.userdefined.info.component.NICComponentInfo; import hirs.attestationca.persist.entity.userdefined.report.DeviceInfoReport; import hirs.attestationca.persist.enums.AppraisalStatus; import hirs.utils.enums.DeviceInfoEnums; @@ -34,8 +42,12 @@ import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.BufferedReader; import java.io.File; @@ -201,12 +213,21 @@ public class SupplyChainCredentialValidatorTest { private static final String NEW_NUC1 = "/validation/platform_credentials/Intel_pc3.cer"; - private static HardwareInfo hardwareInfo; - private static KeyStore keyStore; private static KeyStore emptyKeyStore; + @Mock + private ComponentResultRepository componentResultRepository; + + @Mock + private ComponentAttributeRepository componentAttributeRepository; + + /** + * Holds the AutoCloseable instance returned by openMocks. + */ + private AutoCloseable mocks; + /** * Sets up a KeyStore for testing. * @@ -246,183 +267,38 @@ public class SupplyChainCredentialValidatorTest { } } - private static DeviceInfoReport setupDeviceInfoReport() { - hardwareInfo = new HardwareInfo( - "ACME", - "anvil", - "3.0", - "1234", - "567", - "890"); - - DeviceInfoReport deviceInfoReport = mock(DeviceInfoReport.class); - when(deviceInfoReport.getHardwareInfo()).thenReturn(hardwareInfo); - return deviceInfoReport; - } - - private static DeviceInfoReport setupDeviceInfoReportWithComponents() throws IOException { - return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT); - } - - private static DeviceInfoReport setupDeviceInfoReportWithNotSpecifiedComponents() - throws IOException { - return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_NOT_SPECIFIED_TXT); - } - - private static DeviceInfoReport setupDeviceInfoReportWithComponents( - final String paccorOutputResource) throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); - URL url = SupplyChainCredentialValidator.class.getResource(paccorOutputResource); - String paccorOutputString = IOUtils.toString(url, StandardCharsets.UTF_8); - when(deviceInfoReport.getPaccorOutputString()).thenReturn(paccorOutputString); - return deviceInfoReport; + /** + * Setup mocks. + */ + @BeforeEach + public void setUpBeforeEach() { + mocks = MockitoAnnotations.openMocks(this); } /** - * Creates a new RSA 1024-bit KeyPair using a Bouncy Castle Provider. + * Tears down the mock instances. * - * @return new KeyPair + * @throws Exception if there are any issues closing down mock instances */ - private static KeyPair createKeyPair() { - final int keySize = 1024; - KeyPairGenerator gen; - KeyPair keyPair = null; - try { - gen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); - gen.initialize(keySize, SECURE_RANDOM); - keyPair = gen.generateKeyPair(); - } catch (NoSuchAlgorithmException | NoSuchProviderException e) { - fail("Error occurred while generating key pair", e); - } - return keyPair; - } - - /** - * Create a new X.509 attribute certificate given the holder cert, the signing cert, and the - * signing key. - * - * @param targetCert X509Certificate that will be the holder of the attribute cert - * @param signingCert X509Certificate used to sign the new attribute cert - * @param caPrivateKey PrivateKey used to sign the new attribute cert - * @return new X509AttributeCertificate - */ - private static X509AttributeCertificateHolder createAttributeCert( - final X509Certificate targetCert, final X509Certificate signingCert, - final PrivateKey caPrivateKey) { - X509AttributeCertificateHolder cert = null; - try { - final int timeRange = 50000; - AttributeCertificateHolder holder = - new AttributeCertificateHolder(new X509CertificateHolder( - targetCert.getEncoded())); - AttributeCertificateIssuer issuer = - new AttributeCertificateIssuer(new X500Name(signingCert - .getSubjectX500Principal().getName())); - BigInteger serialNumber = BigInteger.ONE; - Date notBefore = new Date(System.currentTimeMillis() - timeRange); - Date notAfter = new Date(System.currentTimeMillis() + timeRange); - X509v2AttributeCertificateBuilder builder = - new X509v2AttributeCertificateBuilder(holder, issuer, serialNumber, notBefore, - notAfter); - - ContentSigner signer = - new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC") - .build(caPrivateKey); - - cert = builder.build(signer); - } catch (CertificateEncodingException | IOException | OperatorCreationException e) { - fail("Exception occurred while creating a cert", e); - } - - return cert; - - } - - /** - * Create a new X.509 public-key certificate signed by the given certificate. - * - * @param keyPair KeyPair to create the cert for - * @param signingKey PrivateKey of the signing cert - * @param signingCert signing cert - * @return new X509Certificate - */ - private static X509Certificate createCertSignedByAnotherCert(final KeyPair keyPair, - final PrivateKey signingKey, - final X509Certificate signingCert) { - final int timeRange = 10000; - X509Certificate cert = null; - try { - - X500Name issuerName = new X500Name(signingCert.getSubjectX500Principal().getName()); - X500Name subjectName = new X500Name("CN=Test V3 Certificate"); - BigInteger serialNumber = BigInteger.ONE; - Date notBefore = new Date(System.currentTimeMillis() - timeRange); - Date notAfter = new Date(System.currentTimeMillis() + timeRange); - X509v3CertificateBuilder builder = - new JcaX509v3CertificateBuilder(issuerName, serialNumber, notBefore, notAfter, - subjectName, keyPair.getPublic()); - ContentSigner signer = - new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC").build(signingKey); - return new JcaX509CertificateConverter().setProvider("BC").getCertificate( - builder.build(signer)); - } catch (Exception e) { - fail("Exception occurred while creating a cert", e); - } - return cert; - } - - /** - * Creates a self-signed X.509 public-key certificate. - * - * @param pair KeyPair to create the cert for - * @return self-signed X509Certificate - */ - private static X509Certificate createSelfSignedCertificate(final KeyPair pair) { - Security.addProvider(new BouncyCastleProvider()); - final int timeRange = 10000; - X509Certificate cert = null; - try { - - X500Name issuerName = new X500Name("CN=Test Self-Signed V3 Certificate"); - X500Name subjectName = new X500Name("CN=Test Self-Signed V3 Certificate"); - BigInteger serialNumber = BigInteger.ONE; - Date notBefore = new Date(System.currentTimeMillis() - timeRange); - Date notAfter = new Date(System.currentTimeMillis() + timeRange); - X509v3CertificateBuilder builder = - new JcaX509v3CertificateBuilder(issuerName, serialNumber, notBefore, notAfter, - subjectName, pair.getPublic()); - ContentSigner signer = - new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC").build( - pair.getPrivate()); - return new JcaX509CertificateConverter().setProvider("BC").getCertificate( - builder.build(signer)); - } catch (Exception e) { - fail("Exception occurred while creating a cert", e); - } - return cert; - } - - private static InetAddress getTestIpAddress() { - try { - final byte[] byteAddress = new byte[] {127, 0, 0, 1}; - return InetAddress.getByAddress(byteAddress); - } catch (UnknownHostException e) { - return null; + @AfterEach + public void tearDownAfterEach() throws Exception { + if (mocks != null) { + mocks.close(); } } + /** * Checks if the ST Micro Endorsement Credential can be validated against the * ST/GlobalSIgn Certificate Chain. * - * @throws IOException if error occurs while reading files - * @throws URISyntaxException if error occurs while reading files - * @throws CertificateException if error occurs while processing X509 Certs - * @throws KeyStoreException if error occurs while processing Keystore + * @throws IOException if error occurs while reading files + * @throws URISyntaxException if error occurs while reading files + * @throws KeyStoreException if error occurs while processing Keystore */ @Test public final void testValidateEndorsementCredential() - throws URISyntaxException, IOException, CertificateException, KeyStoreException { + throws URISyntaxException, IOException, KeyStoreException { EndorsementCredential ekcert = new EndorsementCredential(Files.readAllBytes( Paths.get(Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI())) @@ -455,14 +331,13 @@ public class SupplyChainCredentialValidatorTest { * Validates a generated cert chain pretending to be from Intel. Credential was generated * with an intermediate CA. This tests the entire chain of validation back to the root CA. * - * @throws IOException if error occurs while reading files - * @throws KeyStoreException if there's an issue string certs to the keystore - * @throws CertificateException if error occurs while ingesting a certificate - * @throws URISyntaxException if a URI can't be processed + * @throws IOException if error occurs while reading files + * @throws KeyStoreException if there's an issue string certs to the keystore + * @throws URISyntaxException if a URI can't be processed */ @Test public final void validateIntelPlatformCredentials() - throws URISyntaxException, IOException, CertificateException, KeyStoreException { + throws URISyntaxException, IOException, KeyStoreException { Certificate intermediatecacert = new CertificateAuthorityCredential(Files.readAllBytes(Paths.get( @@ -502,7 +377,7 @@ public class SupplyChainCredentialValidatorTest { * * @throws Exception If there are errors. */ -// @Test + @Test public final void validateIntelPlatformCredentialAttributes() throws Exception { @@ -512,7 +387,7 @@ public class SupplyChainCredentialValidatorTest { PlatformCredential pc = new PlatformCredential(certBytes); - DeviceInfoReport deviceInfoReport = buildReport( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo( new HardwareInfo(PLATFORM_MANUFACTURER, PLATFORM_MODEL, PLATFORM_VERSION, TEST_BOARD_SERIAL_NUMBER, TEST_CHASSIS_SERIAL_NUMBER, TEST_BOARD_SERIAL_NUMBER)); @@ -520,25 +395,28 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); } + /** * Checks if the Platform Credential contains the serial number from * the device in the platform serial number field. * * @throws Exception If there are errors. */ -// @Test + @Test public final void validatePlatformCredentialWithDeviceBaseboard() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_BOARD_SERIAL_NUMBER)); @@ -552,10 +430,12 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -565,11 +445,11 @@ public class SupplyChainCredentialValidatorTest { * Checks if the Platform Credential contains the serial number from * the device in the chassis serial number field. */ -// @Test + @Test public final void validatePlatformCredentialWithDeviceChassis() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_CHASSIS_SERIAL_NUMBER, DeviceInfoEnums.NOT_SPECIFIED)); @@ -583,10 +463,12 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -598,11 +480,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws Exception If there are errors. */ -// @Test + @Test public final void validatePlatformCredentialWithDeviceSystemSerialNumber() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_BOARD_SERIAL_NUMBER, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED)); @@ -616,10 +498,12 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -629,11 +513,11 @@ public class SupplyChainCredentialValidatorTest { * Checks if validation occurs when the Platform Credential baseboard * serial number is in the device chassis serial number field. */ -// @Test + @Test public final void validatePlatformCredentialCombinedWithChassisSerialNumbersMatchedBaseboard() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_BOARD_SERIAL_NUMBER, DeviceInfoEnums.NOT_SPECIFIED)); @@ -648,10 +532,12 @@ public class SupplyChainCredentialValidatorTest { Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -661,11 +547,11 @@ public class SupplyChainCredentialValidatorTest { * Checks if validation occurs when the Platform Credential chassis * serial number is in the device baseboard serial number field. */ -// @Test + @Test public final void validatePlatformCredentialCombinedWithBaseboardSerialNumbersMatchedChassis() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_CHASSIS_SERIAL_NUMBER)); @@ -679,10 +565,12 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -692,11 +580,11 @@ public class SupplyChainCredentialValidatorTest { * Checks if validation occurs when the Platform Credential chassis * serial number is in the device system serial number field. */ -// @Test + @Test public final void validatePlatformCredentialCombinedWithSystemSerialNumbersMatchedChassis() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport(new HardwareInfo( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo(new HardwareInfo( DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, TEST_CHASSIS_SERIAL_NUMBER, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED)); @@ -710,10 +598,12 @@ public class SupplyChainCredentialValidatorTest { EndorsementCredential ec = new EndorsementCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(TEST_EK_CERT)).toURI()))); + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes(pc, - deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, result.getMessage()); @@ -725,11 +615,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws Exception If there are errors. */ -// @Test + @Test public final void validatePlatformCredentialWithNoDeviceSerialNumbers() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo( new HardwareInfo(PLATFORM_MANUFACTURER, PLATFORM_MODEL, PLATFORM_VERSION, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED)); @@ -746,10 +636,12 @@ public class SupplyChainCredentialValidatorTest { String expectedMessage = "Platform serial did not match device info"; + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes( - pc, deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + pc, deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); assertEquals(expectedMessage, result.getMessage()); } @@ -760,11 +652,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws Exception If there are errors. */ -// @Test + @Test public final void validatePlatformCredentialCombinedWithNoMatchedDeviceSerialNumbers() throws Exception { - DeviceInfoReport deviceInfoReport = buildReport( + DeviceInfoReport deviceInfoReport = buildDeviceInfoReportUsingHardwareInfo( new HardwareInfo(DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, DeviceInfoEnums.NOT_SPECIFIED, "zzz", "aaa", "bbb")); @@ -780,10 +672,12 @@ public class SupplyChainCredentialValidatorTest { String expectedMessage = "Platform serial did not match device info"; + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = CredentialValidator.validatePlatformCredentialAttributes( - pc, deviceInfoReport, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + pc, deviceInfoReport, ec, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); assertEquals(expectedMessage, result.getMessage()); } @@ -855,7 +749,7 @@ public class SupplyChainCredentialValidatorTest { KeyPair caKeyPair = createKeyPair(); KeyPair intermediateKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate intermediateCert = @@ -899,7 +793,7 @@ public class SupplyChainCredentialValidatorTest { KeyPair caKeyPair = createKeyPair(); KeyPair intermediateKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate intermediateCert = @@ -938,7 +832,7 @@ public class SupplyChainCredentialValidatorTest { throws SupplyChainValidatorException { KeyPair caKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate targetCert = @@ -977,7 +871,7 @@ public class SupplyChainCredentialValidatorTest { KeyPair caKeyPair = createKeyPair(); KeyPair intermediateKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate intermediateCert = @@ -1017,7 +911,7 @@ public class SupplyChainCredentialValidatorTest { KeyPair caKeyPair = createKeyPair(); KeyPair intermediateKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate intermediateCert = @@ -1051,7 +945,7 @@ public class SupplyChainCredentialValidatorTest { public final void verifyX509CertificateAgainstCA() throws SupplyChainValidatorException { KeyPair caKeyPair = createKeyPair(); KeyPair targetKeyPair = createKeyPair(); - Set trustedCerts = new HashSet(); + Set trustedCerts = new HashSet<>(); X509Certificate caCert = createSelfSignedCertificate(caKeyPair); X509Certificate targetCert = @@ -1147,7 +1041,7 @@ public class SupplyChainCredentialValidatorTest { * @throws IOException an error occurs when parsing the certificate * @throws URISyntaxException an error occurs parsing the certificate file path */ -// @Test + @Test public final void verifyPlatformCredentialNullDeviceInfoReport() throws URISyntaxException, IOException { byte[] certBytes = Files.readAllBytes(Paths.get( @@ -1162,9 +1056,12 @@ public class SupplyChainCredentialValidatorTest { String expectedMessage = "Can't validate platform credential attributes without a " + "device info report"; + List componentInfoList = retrieveListOfComponentInfos(); + AppraisalStatus result = - CredentialValidator.validatePlatformCredentialAttributes(pc, null, ec, null, null, - Collections.emptyList(), UUID.randomUUID(), false); + CredentialValidator.validatePlatformCredentialAttributes(pc, null, ec, + componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); assertEquals(expectedMessage, result.getMessage()); } @@ -1175,13 +1072,12 @@ public class SupplyChainCredentialValidatorTest { * * @throws URISyntaxException failed to read certificate * @throws IOException failed to read certificate - * @throws KeyStoreException failed to read key store * @throws SupplyChainValidatorException missing credential */ @Test public final void testPlatformDnEquals() throws URISyntaxException, IOException, - KeyStoreException, SupplyChainValidatorException { + SupplyChainValidatorException { Certificate signingCert; signingCert = new CertificateAuthorityCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(INTEL_SIGNING_KEY)).toURI())) @@ -1207,12 +1103,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws URISyntaxException failed to read certificate * @throws IOException failed to read certificate - * @throws KeyStoreException failed to read key store * @throws SupplyChainValidatorException missing credential */ @Test public final void testPlatformDnNotEquals() throws URISyntaxException, IOException, - KeyStoreException, SupplyChainValidatorException { + SupplyChainValidatorException { Certificate signingCert; signingCert = new CertificateAuthorityCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(INTEL_INT_CA)).toURI())) @@ -1237,12 +1132,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws URISyntaxException failed to read certificate * @throws IOException failed to read certificate - * @throws KeyStoreException failed to read key store * @throws SupplyChainValidatorException missing credential */ @Test public final void testEndorsementDnEquals() throws URISyntaxException, IOException, - KeyStoreException, SupplyChainValidatorException { + SupplyChainValidatorException { Certificate signingCert; signingCert = new CertificateAuthorityCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(INT_CA_CERT02)).toURI())) @@ -1268,12 +1162,11 @@ public class SupplyChainCredentialValidatorTest { * * @throws URISyntaxException failed to read certificate * @throws IOException failed to read certificate - * @throws KeyStoreException failed to read key store * @throws SupplyChainValidatorException missing credential */ @Test public final void testEndorsementDnNotEquals() throws URISyntaxException, IOException, - KeyStoreException, SupplyChainValidatorException { + SupplyChainValidatorException { Certificate signingCert; signingCert = new CertificateAuthorityCredential(Files.readAllBytes(Paths.get( Objects.requireNonNull(getClass().getResource(INTEL_INT_CA)).toURI())) @@ -1298,7 +1191,7 @@ public class SupplyChainCredentialValidatorTest { */ @Test public void testMatcher() { - NICComponentInfo nicComponentInfo = new NICComponentInfo("Intel Corporation", + ComponentInfo nicComponentInfo = new ComponentInfo("Intel Corporation", "Ethernet Connection I217-V", "23:94:17:ba:86:5e", "00"); @@ -1334,25 +1227,875 @@ public class SupplyChainCredentialValidatorTest { ); } - private PlatformCredential setupMatchingPlatformCredential( + /** + * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report + * when there are no components. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0NoComponentsPass() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + AppraisalStatus appraisalStatus = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, + componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, + appraisalStatus.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + appraisalStatus.getMessage()); + } + + /** + * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report + * when there are components present. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0WithComponentsPass() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus appraisalStatus = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, + componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, appraisalStatus.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + appraisalStatus.getMessage()); + } + + /** + * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report + * when there are components present, and when the PlatformSerial field holds the system's + * serial number instead of the baseboard serial number. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValPCAttributesV2p0WithComponentsPassPlatformSerialWithSystemSerial() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + when(platformCredential.getPlatformSerial()) + .thenReturn(deviceInfoReport.getHardwareInfo().getSystemSerialNumber()); + + AppraisalStatus appraisalStatus = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, + componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, appraisalStatus.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + appraisalStatus.getMessage()); + } + + /** + * Second test that tests that TPM 2.0 Platform Credentials validate correctly against the device info + * report when there are components present, and when the PlatformSerial field holds the system's + * serial number instead of the baseboard serial number. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + * @throws URISyntaxException failed to read certificate + */ + @Test + public final void testValPCAttributesV2p0WithComponentsPassPlatformSerialWithSystemSerial2() + throws IOException, URISyntaxException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithNotSpecifiedComponents(); + + PlatformCredential platformCredential = new PlatformCredential( + Files.readAllBytes(Paths.get( + Objects.requireNonNull(SupplyChainCredentialValidator.class.getResource( + SAMPLE_TEST_PACCOR_CERT)).toURI()))); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus appraisalStatus = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, + componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, appraisalStatus.getAppStatus()); + } + + /** + * Tests that the SupplyChainCredentialValidator fails when required fields are null. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0RequiredFieldsNull() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + when(platformCredential.getManufacturer()).thenReturn(null); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Platform manufacturer did not match\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + when(platformCredential.getModel()).thenReturn(null); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(result.getAppStatus(), AppraisalStatus.Status.FAIL); + assertEquals(result.getMessage(), "Platform model did not match\n"); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + when(platformCredential.getPlatformSerial()).thenReturn(null); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + when(platformCredential.getVersion()).thenReturn(null); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + List modifiedComponentIdentifiers + = platformCredential.getComponentIdentifiers(); + modifiedComponentIdentifiers.get(0).setComponentManufacturer(null); + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component manufacturer is empty\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + modifiedComponentIdentifiers = platformCredential.getComponentIdentifiers(); + modifiedComponentIdentifiers.get(0).setComponentModel(null); + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component model is empty\n", result.getMessage()); + + } + + /** + * Tests that the SupplyChainCredentialValidator fails when required fields contain only empty + * strings. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0RequiredFieldsEmpty() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part II: Testing using an empty platform manufacturer string + when(platformCredential.getManufacturer()).thenReturn(""); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Platform manufacturer did not match\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part III: Testing using an empty platform model string + when(platformCredential.getModel()).thenReturn(""); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Platform model did not match\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part IV: Testing using an empty platform serial number + when(platformCredential.getPlatformSerial()).thenReturn(""); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Platform serial did not match\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part V: Testing using an empty platform version string + when(platformCredential.getVersion()).thenReturn(""); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Platform version did not match\n", result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part VI: Testing using an empty computer manufacturer string + List modifiedComponentIdentifiers + = platformCredential.getComponentIdentifiers(); + modifiedComponentIdentifiers.get(0).setComponentManufacturer(new DERUTF8String("")); + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component manufacturer is empty\n", + result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + // Part VII: Testing using an empty computer model string + modifiedComponentIdentifiers = platformCredential.getComponentIdentifiers(); + modifiedComponentIdentifiers.get(0).setComponentModel(new DERUTF8String("")); + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component model is empty\n", result.getMessage()); + } + + /** + * Tests that {@link SupplyChainCredentialValidator} fails when a component exists in the + * platform credential, but not in the device info report. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + //@Test + public final void testValidatePlatformCredentialAttributesV2p0MissingComponentInDeviceInfo() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + List modifiedComponentIdentifiers + = platformCredential.getComponentIdentifiers(); + modifiedComponentIdentifiers.add(new ComponentIdentifier( + new DERUTF8String("ACME"), + new DERUTF8String("TNT"), + new DERUTF8String("2"), + new DERUTF8String("1.1"), + null, + ASN1Boolean.FALSE, + Collections.emptyList() + )); + + when(platformCredential.getComponentIdentifiers()).thenReturn( + modifiedComponentIdentifiers + ); + + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("There are unmatched components:\n" + + "Manufacturer=ACME, Model=TNT, Serial=2, Revision=1.1;\n", + result.getMessage()); + } + + /** + * Tests that SupplyChainCredentialValidator passes when everything matches but there are + * extra components in the device info report that are not represented in the platform + * credential. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0ExtraComponentInDeviceInfo() + throws IOException { + PlatformCredential platformCredential = setupMockPlatformCredentialWithPlatformConfigV1( + setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT)); + + // The device info report will contain one extra component. + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents( + SAMPLE_PACCOR_OUTPUT_WITH_EXTRA_COMPONENT_TXT); + + List componentInfoList = retrieveListOfComponentInfos(); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + } + + /** + * Tests that SupplyChainCredentialValidator fails when a component is found in the platform + * credential without a manufacturer or model. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentFieldEmpty() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + List componentIdentifiers + = platformCredential.getComponentIdentifiers(); + componentIdentifiers.get(0).setComponentManufacturer(new DERUTF8String("")); + when(platformCredential.getComponentIdentifiers()).thenReturn(componentIdentifiers); + + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component manufacturer is empty\n", + result.getMessage()); + + platformCredential = setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + + componentIdentifiers = platformCredential.getComponentIdentifiers(); + componentIdentifiers.get(0).setComponentModel(null); + when(platformCredential.getComponentIdentifiers()).thenReturn(componentIdentifiers); + + result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); + assertEquals("Component model is empty\n", result.getMessage()); + } + + /** + * Tests that SupplyChainCredentialValidator passes when a component on the system has a + * matching component in the platform certificate, except the serial value is missing. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentNoSerial() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + ArrayList modifiedIdentifiers = new ArrayList<>(); + for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { + if (identifier.getComponentSerial() != null + && identifier.getComponentSerial().toString().equals("23:94:17:ba:86:5e")) { + identifier.setComponentSerial(new DERUTF8String("")); + } + modifiedIdentifiers.add(identifier); + } + + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + Collections.emptyList(), UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + } + + /** + * Tests that SupplyChainCredentialValidator passes when a component on the system has a + * matching component in the platform certificate, except the revision value is missing. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentNoRevision() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + ArrayList modifiedIdentifiers = new ArrayList<>(); + for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { + if (identifier.getComponentRevision() != null + && identifier.getComponentRevision().toString().equals("00")) { + identifier.setComponentSerial(new DERUTF8String("")); + } + modifiedIdentifiers.add(identifier); + } + + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + } + + /** + * Tests that SupplyChainCredentialValidator passes when a component on the system has a + * matching component in the platform certificate, except the serial and revision values + * are missing. + * + * @throws IOException if unable to set up DeviceInfoReport from resource file + */ + @Test + public final void testValPlatCredentialAttributesV2p0RequiredComponentNoSerialOrRevision() + throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + + PlatformCredential platformCredential = + setupMockPlatformCredentialWithPlatformConfigV1(deviceInfoReport); + + List componentInfoList = retrieveListOfComponentInfos(); + + ArrayList modifiedIdentifiers = new ArrayList<>(); + for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { + if (identifier.getComponentSerial() != null + && identifier.getComponentSerial().toString().equals("23:94:17:ba:86:5e")) { + identifier.setComponentSerial(new DERUTF8String("")); + identifier.setComponentRevision(new DERUTF8String("")); + } + modifiedIdentifiers.add(identifier); + } + + when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); + + AppraisalStatus result = CertificateAttributeScvValidator + .validatePlatformCredentialAttributesV2p0(platformCredential, + deviceInfoReport, componentResultRepository, componentAttributeRepository, + componentInfoList, UUID.randomUUID(), false); + assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); + assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, + result.getMessage()); + } + + /** + * Create a new X.509 attribute certificate given the holder cert, the signing cert, and the + * signing key. + * + * @param targetCert X509Certificate that will be the holder of the attribute cert + * @param signingCert X509Certificate used to sign the new attribute cert + * @param caPrivateKey PrivateKey used to sign the new attribute cert + * @return new X509AttributeCertificate + */ + private X509AttributeCertificateHolder createAttributeCert( + final X509Certificate targetCert, final X509Certificate signingCert, + final PrivateKey caPrivateKey) { + X509AttributeCertificateHolder cert = null; + try { + final int timeRange = 50000; + AttributeCertificateHolder holder = + new AttributeCertificateHolder(new X509CertificateHolder( + targetCert.getEncoded())); + AttributeCertificateIssuer issuer = + new AttributeCertificateIssuer(new X500Name(signingCert + .getSubjectX500Principal().getName())); + BigInteger serialNumber = BigInteger.ONE; + Date notBefore = new Date(System.currentTimeMillis() - timeRange); + Date notAfter = new Date(System.currentTimeMillis() + timeRange); + X509v2AttributeCertificateBuilder builder = + new X509v2AttributeCertificateBuilder(holder, issuer, serialNumber, notBefore, + notAfter); + + ContentSigner signer = + new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC") + .build(caPrivateKey); + + cert = builder.build(signer); + } catch (CertificateEncodingException | IOException | OperatorCreationException e) { + fail("Exception occurred while creating a cert", e); + } + + return cert; + + } + + /** + * Create a new X.509 public-key certificate signed by the given certificate. + * + * @param keyPair KeyPair to create the cert for + * @param signingKey PrivateKey of the signing cert + * @param signingCert signing cert + * @return new X509Certificate + */ + private X509Certificate createCertSignedByAnotherCert(final KeyPair keyPair, + final PrivateKey signingKey, + final X509Certificate signingCert) { + final int timeRange = 10000; + X509Certificate cert = null; + try { + + X500Name issuerName = new X500Name(signingCert.getSubjectX500Principal().getName()); + X500Name subjectName = new X500Name("CN=Test V3 Certificate"); + BigInteger serialNumber = BigInteger.ONE; + Date notBefore = new Date(System.currentTimeMillis() - timeRange); + Date notAfter = new Date(System.currentTimeMillis() + timeRange); + X509v3CertificateBuilder builder = + new JcaX509v3CertificateBuilder(issuerName, serialNumber, notBefore, notAfter, + subjectName, keyPair.getPublic()); + ContentSigner signer = + new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC").build(signingKey); + return new JcaX509CertificateConverter().setProvider("BC").getCertificate( + builder.build(signer)); + } catch (Exception e) { + fail("Exception occurred while creating a cert", e); + } + return cert; + } + + /** + * Creates a self-signed X.509 public-key certificate. + * + * @param pair KeyPair to create the cert for + * @return self-signed X509Certificate + */ + private X509Certificate createSelfSignedCertificate(final KeyPair pair) { + Security.addProvider(new BouncyCastleProvider()); + final int timeRange = 10000; + X509Certificate cert = null; + try { + + X500Name issuerName = new X500Name("CN=Test Self-Signed V3 Certificate"); + X500Name subjectName = new X500Name("CN=Test Self-Signed V3 Certificate"); + BigInteger serialNumber = BigInteger.ONE; + Date notBefore = new Date(System.currentTimeMillis() - timeRange); + Date notAfter = new Date(System.currentTimeMillis() + timeRange); + X509v3CertificateBuilder builder = + new JcaX509v3CertificateBuilder(issuerName, serialNumber, notBefore, notAfter, + subjectName, pair.getPublic()); + ContentSigner signer = + new JcaContentSignerBuilder("SHA1WithRSA").setProvider("BC").build( + pair.getPrivate()); + return new JcaX509CertificateConverter().setProvider("BC").getCertificate( + builder.build(signer)); + } catch (Exception e) { + fail("Exception occurred while creating a cert", e); + } + return cert; + } + + + /** + * Creates a new RSA 1024-bit KeyPair using a Bouncy Castle Provider. + * + * @return new KeyPair + */ + private KeyPair createKeyPair() { + final int keySize = 1024; + KeyPairGenerator gen; + KeyPair keyPair = null; + try { + gen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); + gen.initialize(keySize, SECURE_RANDOM); + keyPair = gen.generateKeyPair(); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + fail("Error occurred while generating key pair", e); + } + return keyPair; + } + + /** + * Helper method that creates a device info report. + * + * @return device info report + */ + private DeviceInfoReport setupDeviceInfoReport() throws UnknownHostException { + + // setup network info + final byte[] byteAddress = new byte[] {127, 0, 0, 1}; + InetAddress inetAddress = InetAddress.getByAddress(byteAddress); + NetworkInfo networkInfo = new NetworkInfo("the-device", inetAddress, new byte[] {1, 0, 1, 0, 1, 0}); + + // setup os info + OSInfo osInfo = new OSInfo("Windows", "11.0", "Not Specified", + "Not Specified", "Not Specified"); + + // setup firmware info + FirmwareInfo firmwareInfo = new FirmwareInfo("Dell Inc", "A11", + "03/12/2013"); + + // setup hardware info + HardwareInfo hardwareInfo = new HardwareInfo( + "ACME", + "anvil", + "3.0", + "1234", + "567", + "890"); + + TPMInfo tpmInfo = new TPMInfo(); + + return new DeviceInfoReport(networkInfo, osInfo, firmwareInfo, hardwareInfo, tpmInfo); + } + + /** + * Helper method that creates a device info report that contains the provided components. + * + * @return device info report that contains provided components + * @throws IOException is thrown if issues arise from parsing out the paccor output + */ + private DeviceInfoReport setupDeviceInfoReportWithComponents() throws IOException { + return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT); + } + + /** + * Helper method that creates a device info report that contains the provided non-specified components. + * + * @return device info report that contains not specified components + * @throws IOException is thrown if issues arise from parsing out the paccor output + */ + private DeviceInfoReport setupDeviceInfoReportWithNotSpecifiedComponents() + throws IOException { + return setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_NOT_SPECIFIED_TXT); + } + + /** + * Helper method that generates a device info report using the provided sample paccor output. + * + * @param paccorOutputResource sample paccor output text + * @return device info report + * @throws IOException is thrown if issues arise from parsing out the paccor output + */ + private DeviceInfoReport setupDeviceInfoReportWithComponents( + final String paccorOutputResource) throws IOException { + DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); + URL url = SupplyChainCredentialValidator.class.getResource(paccorOutputResource); + String paccorOutputString = IOUtils.toString(url, StandardCharsets.UTF_8); + deviceInfoReport.setPaccorOutputString(paccorOutputString); + return deviceInfoReport; + } + + /** + * Helper method that generates a collection of component info that can be used + * for this class' test methods. + * + * @return a generic list of component info + */ + private List retrieveListOfComponentInfos() { + + return List.of( + new ComponentInfo("the-device", "Dell Inc", "11", + "9ZLUO9", "Not Specified", "020000123", + "2.23.133.18.3.1"), + new ComponentInfo("the-device", "9090", "AE12", + "Not Specified", "Not Specified", "00070700", + "2.23.133.18.3.4"), + new ComponentInfo("the-device", "Not Specified", "109 NVM", + "1110_1100_2230_0000_8CE3_8E10_0164_9CC7.", "Not Specified", + "00060001", "2.23.133.18.3.5")); + } + + /** + * Helper method that returns an IP Address. + * + * @return IP address + */ + private InetAddress getTestIpAddress() { + try { + final byte[] byteAddress = new byte[] {127, 0, 0, 1}; + return InetAddress.getByAddress(byteAddress); + } catch (UnknownHostException e) { + return null; + } + } + + /** + * Helper method that mocks out the Platform Credential object (that uses information derived from + * platform configuration V!) used for this class' test methods. + * + * @param deviceInfoReport device info report + * @return mocked out Platform Credential (associated with Platform Configuration V1) + * @throws IOException is thrown if there are any issues using the provided device info report's + * information + */ + private PlatformCredential setupMockPlatformCredentialWithPlatformConfigV1( final DeviceInfoReport deviceInfoReport) throws IOException { PlatformCredential platformCredential = mock(PlatformCredential.class); when(platformCredential.getCredentialType()).thenReturn( PlatformCredential.CERTIFICATE_TYPE_2_0); - when(platformCredential.getManufacturer()) - .thenReturn(hardwareInfo.getManufacturer()); - when(platformCredential.getModel()) - .thenReturn(hardwareInfo.getProductName()); - when(platformCredential.getPlatformSerial()) - .thenReturn(hardwareInfo.getBaseboardSerialNumber()); - when(platformCredential.getVersion()) - .thenReturn(hardwareInfo.getVersion()); - List deviceInfoComponents - = SupplyChainCredentialValidator.getComponentInfoFromPaccorOutput( - deviceInfoReport.getNetworkInfo().getHostname(), - deviceInfoReport.getPaccorOutputString()); + when(platformCredential.getManufacturer()) + .thenReturn(deviceInfoReport.getHardwareInfo().getManufacturer()); + + when(platformCredential.getModel()) + .thenReturn(deviceInfoReport.getHardwareInfo().getProductName()); + + when(platformCredential.getPlatformSerial()) + .thenReturn(deviceInfoReport.getHardwareInfo().getBaseboardSerialNumber()); + + when(platformCredential.getVersion()) + .thenReturn(deviceInfoReport.getHardwareInfo().getVersion()); + + when(platformCredential.getSerialNumber()).thenReturn( + new BigInteger(deviceInfoReport.getHardwareInfo().getSystemSerialNumber())); + + when(platformCredential.getPlatformConfigurationV1()).thenReturn(new PlatformConfigurationV1()); + + List deviceInfoComponents = retrieveListOfComponentInfos(); + List componentIdentifierList = new ArrayList<>(); for (ComponentInfo deviceInfoComponent : deviceInfoComponents) { DERUTF8String serial = null; @@ -1381,560 +2124,105 @@ public class SupplyChainCredentialValidatorTest { } /** - * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report - * when there are no components. + * Helper method that mocks out the Platform Credential object (that uses information derived from + * platform configuration V2) used for this class' test methods. * - * @throws IOException if unable to set up DeviceInfoReport from resource file + * @param deviceInfoReport device info report + * @return mocked out Platform Credential (associated with Platform Configuration V2) + * @throws IOException is thrown if there are any issues using the provided device info report's + * information */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0NoComponentsPass() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReport(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); + private PlatformCredential setupMockPlatformCredentialWithPlatformConfigV2( + final DeviceInfoReport deviceInfoReport) throws IOException { - AppraisalStatus appraisalStatus = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, - appraisalStatus.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - appraisalStatus.getMessage()); - } + PlatformCredential platformCredential = mock(PlatformCredential.class); - /** - * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report - * when there are components present. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0WithComponentsPass() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); + when(platformCredential.getCredentialType()).thenReturn( + PlatformCredential.CERTIFICATE_TYPE_2_0); - AppraisalStatus appraisalStatus = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, appraisalStatus.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - appraisalStatus.getMessage()); - } + when(platformCredential.getManufacturer()) + .thenReturn(deviceInfoReport.getHardwareInfo().getManufacturer()); + + when(platformCredential.getModel()) + .thenReturn(deviceInfoReport.getHardwareInfo().getProductName()); - /** - * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report - * when there are components present, and when the PlatformSerial field holds the system's - * serial number instead of the baseboard serial number. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValPCAttributesV2p0WithComponentsPassPlatformSerialWithSystemSerial() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); when(platformCredential.getPlatformSerial()) - .thenReturn(hardwareInfo.getSystemSerialNumber()); + .thenReturn(deviceInfoReport.getHardwareInfo().getBaseboardSerialNumber()); - AppraisalStatus appraisalStatus = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, appraisalStatus.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - appraisalStatus.getMessage()); - } + when(platformCredential.getVersion()) + .thenReturn(deviceInfoReport.getHardwareInfo().getVersion()); - /** - * Tests that TPM 2.0 Platform Credentials validate correctly against the device info report - * when there are components present, and when the PlatformSerial field holds the system's - * serial number instead of the baseboard serial number. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - * @throws URISyntaxException failed to read certificate - */ -// @Test - public final void testValPCAttributesV2p0WithComponentsPassPlatformSerialWithSystemSerial2() - throws IOException, URISyntaxException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithNotSpecifiedComponents(); - PlatformCredential platformCredential = new PlatformCredential( - Files.readAllBytes(Paths.get( - Objects.requireNonNull(SupplyChainCredentialValidator.class.getResource( - SAMPLE_TEST_PACCOR_CERT)).toURI()))); + when(platformCredential.getSerialNumber()).thenReturn( + new BigInteger(deviceInfoReport.getHardwareInfo().getSystemSerialNumber())); - AppraisalStatus appraisalStatus = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, appraisalStatus.getAppStatus()); - } + when(platformCredential.getPlatformConfigurationV2()).thenReturn(new PlatformConfigurationV2()); - /** - * Tests that the SupplyChainCredentialValidator fails when required fields are null. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0RequiredFieldsNull() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); + List deviceInfoComponents + = retrieveListOfComponentInfos(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getManufacturer()).thenReturn(null); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Platform manufacturer did not match\n", result.getMessage()); + List componentIdentifierV2List = new ArrayList<>(); - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getModel()).thenReturn(null); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(result.getAppStatus(), AppraisalStatus.Status.FAIL); - assertEquals(result.getMessage(), "Platform model did not match\n"); + for (ComponentInfo deviceInfoComponent : deviceInfoComponents) { + DERUTF8String componentSerial = null; + DERUTF8String componentRevision = null; - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getPlatformSerial()).thenReturn(null); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getVersion()).thenReturn(null); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); + ComponentClass componentClass = + new ComponentClass(deviceInfoComponent.getComponentClassValue(), ""); - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - List modifiedComponentIdentifiers - = platformCredential.getComponentIdentifiers(); - modifiedComponentIdentifiers.get(0).setComponentManufacturer(null); - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component manufacturer is empty\n", result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - modifiedComponentIdentifiers = platformCredential.getComponentIdentifiers(); - modifiedComponentIdentifiers.get(0).setComponentModel(null); - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component model is empty\n", result.getMessage()); - - } - - /** - * Tests that the SupplyChainCredentialValidator fails when required fields contain only empty - * strings. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0RequiredFieldsEmpty() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getManufacturer()).thenReturn(""); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Platform manufacturer did not match\n", result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getModel()).thenReturn(""); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Platform model did not match\n", result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getPlatformSerial()).thenReturn(""); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Platform serial did not match\n", result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - when(platformCredential.getVersion()).thenReturn(""); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Platform version did not match\n", result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - List modifiedComponentIdentifiers - = platformCredential.getComponentIdentifiers(); - modifiedComponentIdentifiers.get(0).setComponentManufacturer(new DERUTF8String("")); - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component manufacturer is empty\n" - + "There are unmatched components:\n" - + "Manufacturer=, Model=Core i7, Serial=Not Specified," - + " Revision=Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz;\n", - result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - modifiedComponentIdentifiers = platformCredential.getComponentIdentifiers(); - modifiedComponentIdentifiers.get(0).setComponentModel(new DERUTF8String("")); - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedComponentIdentifiers); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component model is empty\n", result.getMessage()); - } - - /** - * Tests that {@link SupplyChainCredentialValidator} failes when a component exists in the - * platform credential, but not in the device info report. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0MissingComponentInDeviceInfo() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - - List modifiedComponentIdentifiers - = platformCredential.getComponentIdentifiers(); - modifiedComponentIdentifiers.add(new ComponentIdentifier( - new DERUTF8String("ACME"), - new DERUTF8String("TNT"), - new DERUTF8String("2"), - new DERUTF8String("1.1"), - null, - ASN1Boolean.FALSE, - Collections.emptyList() - )); - when(platformCredential.getComponentIdentifiers()).thenReturn( - modifiedComponentIdentifiers - ); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("There are unmatched components:\n" - + "Manufacturer=ACME, Model=TNT, Serial=2, Revision=1.1;\n", - result.getMessage()); - } - - /** - * Tests that SupplyChainCredentialValidator passes when everything matches but there are - * extra components in the device info report that are not represented in the platform - * credential. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0ExtraComponentInDeviceInfo() - throws IOException { - PlatformCredential platformCredential = setupMatchingPlatformCredential( - setupDeviceInfoReportWithComponents(SAMPLE_PACCOR_OUTPUT_TXT)); - - // The device info report will contain one extra component. - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents( - SAMPLE_PACCOR_OUTPUT_WITH_EXTRA_COMPONENT_TXT); - - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - } - - /** - * Tests that SupplyChainCredentialValidator fails when a component is found in the platform - * credential without a manufacturer or model. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentFieldEmpty() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - - List componentIdentifiers - = platformCredential.getComponentIdentifiers(); - componentIdentifiers.get(0).setComponentManufacturer(new DERUTF8String("")); - when(platformCredential.getComponentIdentifiers()).thenReturn(componentIdentifiers); - - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component manufacturer is empty\n" - + "There are unmatched components:\n" - + "Manufacturer=, Model=Core i7, Serial=Not Specified," - + " Revision=Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz;\n", - result.getMessage()); - - platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - - componentIdentifiers = platformCredential.getComponentIdentifiers(); - componentIdentifiers.get(0).setComponentModel(null); - when(platformCredential.getComponentIdentifiers()).thenReturn(componentIdentifiers); - - result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.FAIL, result.getAppStatus()); - assertEquals("Component model is empty\n", result.getMessage()); - } - - /** - * Tests that SupplyChainCredentialValidator passes when a component on the system has a - * matching component in the platform certificate, except the serial value is missing. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentNoSerial() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - - ArrayList modifiedIdentifiers = new ArrayList<>(); - for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { - if (identifier.getComponentSerial() != null - && identifier.getComponentSerial().toString().equals("23:94:17:ba:86:5e")) { - identifier.setComponentSerial(new DERUTF8String("")); + if (deviceInfoComponent.getComponentSerial() != null) { + componentSerial = new DERUTF8String(deviceInfoComponent.getComponentSerial()); } - modifiedIdentifiers.add(identifier); + + if (deviceInfoComponent.getComponentRevision() != null) { + componentRevision = new DERUTF8String(deviceInfoComponent.getComponentRevision()); + } + + componentIdentifierV2List.add(new ComponentIdentifierV2( + componentClass, + new DERUTF8String(deviceInfoComponent.getComponentManufacturer()), + new DERUTF8String(deviceInfoComponent.getComponentModel()), + componentSerial, + componentRevision, + null, + ASN1Boolean.TRUE, + Collections.emptyList(), + new CertificateIdentifier(), + new URIReference(), + AttributeStatus.ADDED + )); + } - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); + when(platformCredential.getComponentIdentifiersV2()).thenReturn(componentIdentifierV2List); - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); + return platformCredential; } /** - * Tests that SupplyChainCredentialValidator passes when a component on the system has a - * matching component in the platform certificate, except the revision value is missing. + * Helper method that uses the provided hardware info to create a device info report. * - * @throws IOException if unable to set up DeviceInfoReport from resource file + * @param givenHardwareInfo hardware info + * @return device info report */ -// @Test - public final void testValidatePlatformCredentialAttributesV2p0RequiredComponentNoRevision() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); + private DeviceInfoReport buildDeviceInfoReportUsingHardwareInfo(final HardwareInfo givenHardwareInfo) { + final InetAddress ipAddress = getTestIpAddress(); + final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66}; - ArrayList modifiedIdentifiers = new ArrayList<>(); - for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { - if (identifier.getComponentRevision() != null - && identifier.getComponentRevision().toString().equals("00")) { - identifier.setComponentSerial(new DERUTF8String("")); - } - modifiedIdentifiers.add(identifier); - } + OSInfo osInfo = new OSInfo(); + NetworkInfo networkInfo = new NetworkInfo("test", ipAddress, macAddress); + FirmwareInfo firmwareInfo = new FirmwareInfo(); + TPMInfo tpmInfo = new TPMInfo(); - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); - - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); - } - - /** - * Tests that SupplyChainCredentialValidator passes when a component on the system has a - * matching component in the platform certificate, except the serial and revision values - * are missing. - * - * @throws IOException if unable to set up DeviceInfoReport from resource file - */ -// @Test - public final void testValPlatCredentialAttributesV2p0RequiredComponentNoSerialOrRevision() - throws IOException { - DeviceInfoReport deviceInfoReport = setupDeviceInfoReportWithComponents(); - PlatformCredential platformCredential = setupMatchingPlatformCredential(deviceInfoReport); - - ArrayList modifiedIdentifiers = new ArrayList<>(); - for (ComponentIdentifier identifier : platformCredential.getComponentIdentifiers()) { - if (identifier.getComponentSerial() != null - && identifier.getComponentSerial().toString().equals("23:94:17:ba:86:5e")) { - identifier.setComponentSerial(new DERUTF8String("")); - identifier.setComponentRevision(new DERUTF8String("")); - } - modifiedIdentifiers.add(identifier); - } - - when(platformCredential.getComponentIdentifiers()).thenReturn(modifiedIdentifiers); - - AppraisalStatus result = CertificateAttributeScvValidator - .validatePlatformCredentialAttributesV2p0(platformCredential, - deviceInfoReport, null, null, - Collections.emptyList(), UUID.randomUUID(), false); - assertEquals(AppraisalStatus.Status.PASS, result.getAppStatus()); - assertEquals(SupplyChainCredentialValidator.PLATFORM_ATTRIBUTES_VALID, - result.getMessage()); + return new DeviceInfoReport(networkInfo, osInfo, + firmwareInfo, givenHardwareInfo, tpmInfo); } /** * Tests that SupplyChainCredentialValidator passes with a base and delta certificate where * the base serial number and delta holder serial number match. * - * @throws java.io.IOException Reading file for the certificates - * @throws java.net.URISyntaxException when loading certificates bytes + * @throws IOException Reading file for the certificates + * @throws URISyntaxException when loading certificates bytes */ // @Test public final void testValidateDeltaPlatformCredentialAttributes() @@ -1990,22 +2278,22 @@ public class SupplyChainCredentialValidatorTest { // ComponentIdentifierV2 ciV21Faulty = new ComponentIdentifierV2(); // ComponentIdentifierV2 ciV22Faulty = new ComponentIdentifierV2(); // ciV21Faulty.setComponentManufacturer(compId2.getComponentManufacturer()); -// ciV21Faulty.setComponentClass(compId2.getComponentClass()); +// ciV21Faulty.setComponentClass(compId2.getComponentClassValue()); // ciV21Faulty.setComponentModel(compId2.getComponentModel()); // ciV21Faulty.setComponentSerial(compId2.getComponentSerial()); // ciV21Faulty.setComponentRevision(compId2.getComponentRevision()); // ciV21Faulty.setComponentManufacturerId(compId2.getComponentManufacturerId()); // ciV21Faulty.setFieldReplaceable(compId2.getFieldReplaceable()); -// ciV21Faulty.setComponentAddress(compId2.getComponentAddress()); +// ciV21Faulty.setComponentAddresses(compId2.getComponentAddresses()); // ciV21Faulty.setAttributeStatus(AttributeStatus.REMOVED); // ciV22Faulty.setComponentManufacturer(compId3.getComponentManufacturer()); -// ciV22Faulty.setComponentClass(compId3.getComponentClass()); +// ciV22Faulty.setComponentClass(compId3.getComponentClassValue()); // ciV22Faulty.setComponentModel(compId3.getComponentModel()); // ciV22Faulty.setComponentSerial(compId3.getComponentSerial()); // ciV22Faulty.setComponentRevision(compId3.getComponentRevision()); // ciV22Faulty.setComponentManufacturerId(compId3.getComponentManufacturerId()); // ciV22Faulty.setFieldReplaceable(compId3.getFieldReplaceable()); -// ciV22Faulty.setComponentAddress(compId3.getComponentAddress()); +// ciV22Faulty.setComponentAddresses(compId3.getComponentAddresses()); // ciV22Faulty.setAttributeStatus(AttributeStatus.REMOVED); // // List compList = new ArrayList<>(3); @@ -2070,8 +2358,8 @@ public class SupplyChainCredentialValidatorTest { * Tests that SupplyChainCredentialValidator fails when a component needs to * be replaced but hasn't been by a delta certificate. * - * @throws java.io.IOException Reading file for the certificates - * @throws java.net.URISyntaxException when loading certificates bytes + * @throws IOException Reading file for the certificates + * @throws URISyntaxException when loading certificates bytes */ // @Test public final void testValidateChainFailure() @@ -2123,7 +2411,7 @@ public class SupplyChainCredentialValidatorTest { // ciV21Faulty.setComponentRevision(compId2.getComponentRevision()); // ciV21Faulty.setComponentManufacturerId(compId2.getComponentManufacturerId()); // ciV21Faulty.setFieldReplaceable(compId2.getFieldReplaceable()); -// ciV21Faulty.setComponentAddress(compId2.getComponentAddress()); +// ciV21Faulty.setComponentAddresses(compId2.getComponentAddresses()); // ciV21Faulty.setAttributeStatus(AttributeStatus.REMOVED); // ciV22Faulty.setComponentManufacturer(compId3.getComponentManufacturer()); // ciV22Faulty.setComponentModel(compId3.getComponentModel()); @@ -2131,7 +2419,7 @@ public class SupplyChainCredentialValidatorTest { // ciV22Faulty.setComponentRevision(compId3.getComponentRevision()); // ciV22Faulty.setComponentManufacturerId(compId3.getComponentManufacturerId()); // ciV22Faulty.setFieldReplaceable(compId3.getFieldReplaceable()); -// ciV22Faulty.setComponentAddress(compId3.getComponentAddress()); +// ciV22Faulty.setComponentAddresses(compId3.getComponentAddresses()); // ciV22Faulty.setAttributeStatus(AttributeStatus.REMOVED); // // List compList = new ArrayList<>(3); @@ -2180,16 +2468,5 @@ public class SupplyChainCredentialValidatorTest { // result.getMessage()); } - private DeviceInfoReport buildReport(final HardwareInfo givenHardwareInfo) { - final InetAddress ipAddress = getTestIpAddress(); - final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66}; - OSInfo osInfo = new OSInfo(); - NetworkInfo networkInfo = new NetworkInfo("test", ipAddress, macAddress); - FirmwareInfo firmwareInfo = new FirmwareInfo(); - TPMInfo tpmInfo = new TPMInfo(); - - return new DeviceInfoReport(networkInfo, osInfo, - firmwareInfo, givenHardwareInfo, tpmInfo); - } } diff --git a/HIRS_AttestationCAPortal/build.gradle b/HIRS_AttestationCAPortal/build.gradle index 855ab51e..47911ead 100644 --- a/HIRS_AttestationCAPortal/build.gradle +++ b/HIRS_AttestationCAPortal/build.gradle @@ -83,10 +83,6 @@ dependencies { testImplementation libs.xmlunit.core } -test { - useJUnitPlatform() -} - task buildVersion() { doLast { def verFile = new File(projectDir, "build/VERSION") diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificatePageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificatePageController.java index 4639e411..49a82ecc 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificatePageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificatePageController.java @@ -19,6 +19,7 @@ import hirs.attestationca.persist.entity.userdefined.certificate.IDevIDCertifica import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.util.CredentialHelper; import hirs.attestationca.portal.datatables.DataTableInput; import hirs.attestationca.portal.datatables.DataTableResponse; @@ -348,7 +349,7 @@ public class CertificatePageController extends PageController { records.setRecordsFiltered(caCredentialRepository.findByArchiveFlag(false).size()); - log.debug("Returning the size of the list of certificate trust chains: {}", records.size()); + log.debug("Returning the size of the list of trust chain certificates: {}", records.size()); return new DataTableResponse<>(records, input); } case ISSUEDCERTIFICATES -> { @@ -957,7 +958,7 @@ public class CertificatePageController extends PageController { } this.certificateRepository.save(certificate); - handlePlatformComponents(certificate); + parseAndSaveComponentResults(certificate); final String successMsg = String.format("New certificate successfully uploaded (%s): ", fileName); @@ -971,6 +972,11 @@ public class CertificatePageController extends PageController { messages.addError(failMessage + dbsEx.getMessage()); log.error(failMessage, dbsEx); return; + } catch (IOException ioException) { + final String ioExceptionMessage = "Failed to save component results in the database"; + messages.addError(ioExceptionMessage + ioException.getMessage()); + log.error(ioExceptionMessage, ioException); + return; } try { @@ -1019,7 +1025,7 @@ public class CertificatePageController extends PageController { * * @param certificate certificate */ - private void handlePlatformComponents(final Certificate certificate) { + private void parseAndSaveComponentResults(final Certificate certificate) throws IOException { PlatformCredential platformCredential; if (certificate instanceof PlatformCredential) { @@ -1028,19 +1034,38 @@ public class CertificatePageController extends PageController { .findByCertificateSerialNumberAndBoardSerialNumber( platformCredential.getSerialNumber().toString(), platformCredential.getPlatformSerial()); + if (componentResults.isEmpty()) { ComponentResult componentResult; - List componentIdentifiers = platformCredential.getComponentIdentifiers(); + if (platformCredential.getPlatformConfigurationV1() != null) { - for (ComponentIdentifier componentIdentifier : componentIdentifiers) { - componentResult = new ComponentResult(platformCredential.getPlatformSerial(), - platformCredential.getSerialNumber().toString(), - platformCredential.getPlatformChainType(), - componentIdentifier); - componentResult.setFailedValidation(false); - componentResult.setDelta(!platformCredential.isPlatformBase()); - componentResultRepository.save(componentResult); + List componentIdentifiers = + platformCredential.getComponentIdentifiers(); + + for (ComponentIdentifier componentIdentifier : componentIdentifiers) { + componentResult = new ComponentResult(platformCredential.getPlatformSerial(), + platformCredential.getSerialNumber().toString(), + platformCredential.getPlatformChainType(), + componentIdentifier); + componentResult.setFailedValidation(false); + componentResult.setDelta(!platformCredential.isPlatformBase()); + componentResultRepository.save(componentResult); + } + } else if (platformCredential.getPlatformConfigurationV2() != null) { + + List componentIdentifiersV2 = + platformCredential.getComponentIdentifiersV2(); + + for (ComponentIdentifierV2 componentIdentifierV2 : componentIdentifiersV2) { + componentResult = new ComponentResult(platformCredential.getPlatformSerial(), + platformCredential.getSerialNumber().toString(), + platformCredential.getPlatformChainType(), + componentIdentifierV2); + componentResult.setFailedValidation(false); + componentResult.setDelta(!platformCredential.isPlatformBase()); + componentResultRepository.save(componentResult); + } } } else { for (ComponentResult componentResult : componentResults) { diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java index 30d11444..51d340bd 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/utils/CertificateStringMapBuilder.java @@ -11,7 +11,9 @@ import hirs.attestationca.persist.entity.userdefined.certificate.IDevIDCertifica import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate; import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; -import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfiguration; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.PlatformConfigurationV1; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.PlatformConfigurationV2; import hirs.attestationca.persist.util.AcaPciIds; import hirs.utils.BouncyCastleUtils; import hirs.utils.PciIds; @@ -401,22 +403,39 @@ public final class CertificateStringMapBuilder { data.put("componentResults", compResults); //Get platform Configuration values and set map with it - PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration(); - if (platformConfiguration != null) { - //Component Identifier - attempt to translate hardware IDs - List comps = platformConfiguration.getComponentIdentifier(); + if (certificate.getPlatformConfigurationV1() != null) { + PlatformConfigurationV1 platformConfigurationV1 = certificate.getPlatformConfigurationV1(); + + List componentIdentifiersV1 = + platformConfigurationV1.getComponentIdentifiers(); + if (PciIds.DB.isReady()) { - comps = AcaPciIds.translate(comps); + componentIdentifiersV1 = AcaPciIds.translate(componentIdentifiersV1); } - data.put("componentsIdentifier", comps); - //Component Identifier URI - data.put("componentsIdentifierURI", platformConfiguration - .getComponentIdentifierUri()); + //Component Identifiers + data.put("componentsIdentifier", componentIdentifiersV1); + //Platform Properties - data.put("platformProperties", platformConfiguration.getPlatformProperties()); + data.put("platformProperties", platformConfigurationV1.getPlatformProperties()); //Platform Properties URI - data.put("platformPropertiesURI", platformConfiguration.getPlatformPropertiesUri()); + data.put("platformPropertiesURI", platformConfigurationV1.getPlatformPropertiesUri()); + + } else if (certificate.getPlatformConfigurationV2() != null) { + PlatformConfigurationV2 platformConfigurationV2 = certificate.getPlatformConfigurationV2(); + //Component Identifiers + List componentIdentifiersV2 = + platformConfigurationV2.getComponentIdentifiers(); + + data.put("componentsIdentifier", componentIdentifiersV2); + //Component Identifier URI + data.put("componentsIdentifierURI", platformConfigurationV2 + .getComponentIdentifiersUri()); + //Platform Properties + data.put("platformProperties", platformConfigurationV2.getPlatformProperties()); + //Platform Properties URI + data.put("platformPropertiesURI", platformConfigurationV2.getPlatformPropertiesUri()); } + //TBB Security Assertion data.put("tbbSecurityAssertion", certificate.getTBBSecurityAssertion()); diff --git a/HIRS_Structs/build.gradle b/HIRS_Structs/build.gradle index 8bc6d11b..271ea1df 100644 --- a/HIRS_Structs/build.gradle +++ b/HIRS_Structs/build.gradle @@ -16,10 +16,6 @@ dependencies { testAnnotationProcessor libs.lombok } -test { - useJUnitPlatform() -} - //publishing { // publications { // maven(MavenPublication) { diff --git a/HIRS_Utils/build.gradle b/HIRS_Utils/build.gradle index 8ba2e5c2..cd9811b2 100644 --- a/HIRS_Utils/build.gradle +++ b/HIRS_Utils/build.gradle @@ -42,10 +42,6 @@ dependencies { testAnnotationProcessor libs.lombok } -test { - useJUnitPlatform() -} - jar { duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { diff --git a/build.gradle b/build.gradle index 73f8a56c..40406567 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ plugins { id 'com.github.spotbugs' version '6.0.13' apply false id 'org.owasp.dependencycheck' version '11.1.1' id 'java' + id 'jacoco' } // Global checkstyle file @@ -19,6 +20,7 @@ subprojects { apply plugin: "java" apply plugin: "checkstyle" apply plugin: "org.owasp.dependencycheck" + apply plugin: "jacoco" repositories { flatDir { dirs "lib" } @@ -31,6 +33,20 @@ subprojects { } } + jacoco { + toolVersion = '0.8.12' + } + + if (project.name != 'tcg_rim_tool') // run tests on every subproject except for rim_tools + test { + useJUnitPlatform() // Use JUnit platform + finalizedBy jacocoTestReport // Generate the JaCoCo report after running tests + } + + jacocoTestReport { + dependsOn test // tests are required to run before generating the report + } + checkstyle { toolVersion = '10.20.0' configFile file("${rootDir}/config/checkstyle/checkstyle.xml") @@ -61,7 +77,6 @@ subprojects { } } - dependencies { repositories { // Use Maven Central for resolving dependencies. diff --git a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java index 06254b4c..f34fa75c 100644 --- a/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java +++ b/tools/tcg_rim_tool/src/test/java/hirs/swid/TestSwidTagGateway.java @@ -1,45 +1,56 @@ package hirs.swid; import hirs.utils.rim.ReferenceManifestValidator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.test.context.event.annotation.AfterTestClass; -import org.springframework.test.context.event.annotation.BeforeTestClass; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertTrue; - +//TODO tests are broken public class TestSwidTagGateway { + private static final String ATTRIBUTES_FILE = Objects.requireNonNull( + TestSwidTagGateway.class.getClassLoader() + .getResource("rim_fields.json")).getPath(); + + private static final String CA_CHAIN_FILE = Objects.requireNonNull( + TestSwidTagGateway.class.getClassLoader() + .getResource("RimCertChain.pem")).getPath(); + + private static final String SUPPORT_RIM_FILE = Objects.requireNonNull( + TestSwidTagGateway.class.getClassLoader() + .getResource("TpmLog.bin")).getPath(); + + private static SwidTagGateway gateway; + + private static ReferenceManifestValidator validator; + private final String DEFAULT_OUTPUT = "generated_swidTag.swidtag"; + private final String BASE_USER_CERT = "generated_user_cert.swidtag"; - private final String BASE_USER_CERT_EMBED = "generated_user_cert_embed.swidtag"; - private final String BASE_DEFAULT_CERT = "generated_default_cert.swidtag"; - private final String BASE_RFC3339_TIMESTAMP = "generated_timestamp_rfc3339.swidtag"; - private final String BASE_RFC3852_TIMESTAMP = "generated_timestamp_rfc3852.swidtag"; - private final String ATTRIBUTES_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("rim_fields.json").getPath(); - private final String JKS_KEYSTORE_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("keystore.jks").getPath(); - private final String SIGNING_CERT_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("RimSignCert.pem").getPath(); - private final String PRIVATE_KEY_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("privateRimKey.pem").getPath(); - private final String CA_CHAIN_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("RimCertChain.pem").getPath(); - private final String SUPPORT_RIM_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("TpmLog.bin").getPath(); - private final String RFC3852_COUNTERSIGNATURE_FILE = TestSwidTagGateway.class.getClassLoader() - .getResource("counterSignature.file").getPath(); - private SwidTagGateway gateway; - private ReferenceManifestValidator validator; + + private final String JKS_KEYSTORE_FILE = Objects.requireNonNull(TestSwidTagGateway.class.getClassLoader() + .getResource("keystore.jks")).getPath(); + + private final String SIGNING_CERT_FILE = Objects.requireNonNull(TestSwidTagGateway.class.getClassLoader() + .getResource("RimSignCert.pem")).getPath(); + + private final String PRIVATE_KEY_FILE = Objects.requireNonNull(TestSwidTagGateway.class.getClassLoader() + .getResource("privateRimKey.pem")).getPath(); + + private final String RFC3852_COUNTERSIGNATURE_FILE = Objects.requireNonNull( + TestSwidTagGateway.class.getClassLoader() + .getResource("counterSignature.file")).getPath(); + private InputStream expectedFile; - @BeforeTestClass - public void setUp() throws Exception { + @BeforeAll + public static void setUp() { gateway = new SwidTagGateway(); gateway.setRimEventLog(SUPPORT_RIM_FILE); gateway.setAttributesFile(ATTRIBUTES_FILE); @@ -48,7 +59,7 @@ public class TestSwidTagGateway { validator.setTrustStoreFile(CA_CHAIN_FILE); } - @AfterTestClass + @AfterEach public void tearDown() throws Exception { if (expectedFile != null) { expectedFile.close(); @@ -87,6 +98,7 @@ public class TestSwidTagGateway { gateway.setPemPrivateKeyFile(PRIVATE_KEY_FILE); gateway.setEmbeddedCert(true); gateway.generateSwidTag(DEFAULT_OUTPUT); + final String BASE_USER_CERT_EMBED = "generated_user_cert_embed.swidtag"; expectedFile = TestSwidTagGateway.class.getClassLoader() .getResourceAsStream(BASE_USER_CERT_EMBED); assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); @@ -103,6 +115,7 @@ public class TestSwidTagGateway { gateway.setDefaultCredentials(true); gateway.setJksTruststoreFile(JKS_KEYSTORE_FILE); gateway.generateSwidTag(DEFAULT_OUTPUT); + final String BASE_DEFAULT_CERT = "generated_default_cert.swidtag"; expectedFile = TestSwidTagGateway.class.getClassLoader() .getResourceAsStream(BASE_DEFAULT_CERT); assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); @@ -121,6 +134,7 @@ public class TestSwidTagGateway { gateway.setTimestampFormat("RFC3339"); gateway.setTimestampArgument("2023-01-01T00:00:00Z"); gateway.generateSwidTag(DEFAULT_OUTPUT); + final String BASE_RFC3339_TIMESTAMP = "generated_timestamp_rfc3339.swidtag"; expectedFile = TestSwidTagGateway.class.getClassLoader() .getResourceAsStream(BASE_RFC3339_TIMESTAMP); assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); @@ -139,6 +153,7 @@ public class TestSwidTagGateway { gateway.setTimestampFormat("RFC3852"); gateway.setTimestampArgument(RFC3852_COUNTERSIGNATURE_FILE); gateway.generateSwidTag(DEFAULT_OUTPUT); + final String BASE_RFC3852_TIMESTAMP = "generated_timestamp_rfc3852.swidtag"; expectedFile = TestSwidTagGateway.class.getClassLoader() .getResourceAsStream(BASE_RFC3852_TIMESTAMP); assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT)); @@ -150,10 +165,10 @@ public class TestSwidTagGateway { * This test corresponds to the arguments: * -v */ - - public void testvalidateSwidtagFile() { - String filepath = TestSwidTagGateway.class.getClassLoader() - .getResource(BASE_USER_CERT).getPath(); + @Test + public void testValidateSwidtagFile() { + final String filepath = Objects.requireNonNull(TestSwidTagGateway.class.getClassLoader() + .getResource(BASE_USER_CERT)).getPath(); System.out.println("Validating file at " + filepath); validator.setRim(DEFAULT_OUTPUT); assertTrue(validator.validateRim(SIGNING_CERT_FILE)); @@ -178,13 +193,7 @@ public class TestSwidTagGateway { return false; } } - } catch (FileNotFoundException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { - e.printStackTrace(); - return false; - } catch (NullPointerException e) { + } catch (IOException | NullPointerException e) { e.printStackTrace(); return false; } finally { From 436b0482c488c021971109a2cd09b5136ddf1d86 Mon Sep 17 00:00:00 2001 From: 5B96790E3664F40075A67E6ADF737EDB15B4408DBC91A81228B31537B0CE3E26 <33426478+iadgovuser29@users.noreply.github.com> Date: Wed, 9 Apr 2025 07:15:51 -0400 Subject: [PATCH 2/9] Provisioner to use updated registry libraries (#914) * Registry libraries 0.7.5 * Update reference --- HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj b/HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj index d5b46767..a9bc7977 100644 --- a/HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj +++ b/HIRS_Provisioner.NET/hirs/HIRS_Provisioner.NET.csproj @@ -36,9 +36,9 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive From d9dafb052654f4b9da3eb5bacd950df0f64c5d36 Mon Sep 17 00:00:00 2001 From: 5B96790E3664F40075A67E6ADF737EDB15B4408DBC91A81228B31537B0CE3E26 <33426478+iadgovuser29@users.noreply.github.com> Date: Wed, 9 Apr 2025 10:58:14 -0400 Subject: [PATCH 3/9] Take only first cert in multi part PEM (#916) * Take only first cert in multi part PEM, minimize side effects * Other cases * Github Actions dropping their ubuntu 20 runner --- .github/workflows/dotnet_provisioner_unit_tests.yml | 2 +- .../attestationca/persist/util/CredentialHelper.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnet_provisioner_unit_tests.yml b/.github/workflows/dotnet_provisioner_unit_tests.yml index 6fa613dc..97e2d209 100644 --- a/.github/workflows/dotnet_provisioner_unit_tests.yml +++ b/.github/workflows/dotnet_provisioner_unit_tests.yml @@ -13,7 +13,7 @@ jobs: matrix: include: - os: windows-2022 - - os: ubuntu-20.04 + - os: ubuntu-22.04 # - os: windows-2019 Cannot Target windows-2019 because the .NET 6 SDK won't receive security patches for this image steps: - name: Set git to use LF diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/CredentialHelper.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/CredentialHelper.java index be6a08e5..5e202564 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/CredentialHelper.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/util/CredentialHelper.java @@ -58,9 +58,15 @@ public final class CredentialHelper { public static byte[] stripPemHeaderFooter(final String pemFile) { String strippedFile; strippedFile = pemFile.replace(CertificateVariables.PEM_HEADER, ""); - strippedFile = strippedFile.replace(CertificateVariables.PEM_FOOTER, ""); + int keyFooterPos = strippedFile.indexOf(CertificateVariables.PEM_FOOTER); + if (keyFooterPos >= 0) { + strippedFile = strippedFile.substring(0, keyFooterPos); + } strippedFile = strippedFile.replace(CertificateVariables.PEM_ATTRIBUTE_HEADER, ""); - strippedFile = strippedFile.replace(CertificateVariables.PEM_ATTRIBUTE_FOOTER, ""); + int attrFooterPos = strippedFile.indexOf(CertificateVariables.PEM_ATTRIBUTE_FOOTER); + if (attrFooterPos >= 0) { + strippedFile = strippedFile.substring(0, attrFooterPos); + } return Base64.decode(strippedFile); } From cb6c98cafbb5954317b8327e8eacf22907673b2d Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:08:43 -0400 Subject: [PATCH 4/9] Upgrade ubuntu image in dotnet provisioner workflow (#918) --- .github/workflows/dotnet_provisioner_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet_provisioner_unit_tests.yml b/.github/workflows/dotnet_provisioner_unit_tests.yml index 97e2d209..cc4e6de1 100644 --- a/.github/workflows/dotnet_provisioner_unit_tests.yml +++ b/.github/workflows/dotnet_provisioner_unit_tests.yml @@ -13,7 +13,7 @@ jobs: matrix: include: - os: windows-2022 - - os: ubuntu-22.04 + - os: ubuntu-latest # - os: windows-2019 Cannot Target windows-2019 because the .NET 6 SDK won't receive security patches for this image steps: - name: Set git to use LF From e2952baf4bf59cad11140919d12f41512c59d7ff Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Thu, 9 Jan 2025 00:40:41 -0500 Subject: [PATCH 5/9] Separate RIM and PCR value validations into distinct methods --- .../validation/FirmwareScvValidator.java | 395 ++++++++++-------- 1 file changed, 215 insertions(+), 180 deletions(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java index e4af6686..c7ac85ec 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java @@ -38,6 +38,7 @@ import static hirs.attestationca.persist.enums.AppraisalStatus.Status.PASS; public class FirmwareScvValidator extends SupplyChainCredentialValidator { private static PcrValidator pcrValidator; + private static ReferenceManifest supportReferenceManifest; /** * @param device device @@ -54,17 +55,11 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { final ReferenceDigestValueRepository referenceDigestValueRepository, final CACredentialRepository caCredentialRepository) { boolean passed = true; - String[] baseline = new String[Integer.SIZE]; AppraisalStatus fwStatus = null; String hostName = device.getDeviceInfo().getNetworkInfo().getHostname(); -// ReferenceManifest validationObject; - List baseReferenceManifests = null; BaseReferenceManifest baseReferenceManifest = null; - ReferenceManifest supportReferenceManifest = null; EventLogMeasurements measurement = null; - //baseReferenceManifests = referenceManifestRepository.findAllBaseRims(); - // This block was looking for a base RIM matching the device name // The base rim might not have a device name associated with it- i.e. if it's uploaded to the ACA // prior to provisioning In this case, try to look up the event log associated with the device, @@ -108,182 +103,24 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { } if (passed) { - List resources = - baseReferenceManifest.getFileResources(); - fwStatus = new AppraisalStatus(PASS, - SupplyChainCredentialValidator.FIRMWARE_VALID); - - // verify signatures - ReferenceManifestValidator referenceManifestValidator = - new ReferenceManifestValidator(); - referenceManifestValidator.setRim(baseReferenceManifest.getRimBytes()); - - //Validate signing cert - List allCerts = caCredentialRepository.findAll(); - CertificateAuthorityCredential signingCert = null; - for (CertificateAuthorityCredential cert : allCerts) { - signingCert = cert; - KeyStore keyStore = null; - Set set = ValidationService.getCaChainRec(signingCert, - Collections.emptySet(), - caCredentialRepository); - try { - keyStore = ValidationService.caCertSetToKeystore(set); - } catch (Exception e) { - log.error("Error building CA chain for {}: {}", signingCert.getSubjectKeyIdentifier(), - e.getMessage()); - } - - ArrayList certs = new ArrayList<>(set.size()); - for (CertificateAuthorityCredential cac : set) { - try { - certs.add(cac.getX509Certificate()); - } catch (IOException e) { - log.error("Error building CA chain for {}: {}", signingCert.getSubjectKeyIdentifier(), - e.getMessage()); - } - } - referenceManifestValidator.setTrustStore(certs); - try { - if (referenceManifestValidator.validateXmlSignature( - signingCert.getX509Certificate().getPublicKey(), - signingCert.getSubjectKeyIdString(), signingCert.getEncodedPublicKey())) { - try { - if (!SupplyChainCredentialValidator.verifyCertificate( - signingCert.getX509Certificate(), keyStore)) { - passed = false; - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: invalid certificate path."); - } - } catch (IOException ioEx) { - log.error("Error getting X509 cert from manager: {}", ioEx.getMessage()); - } catch (SupplyChainValidatorException scvEx) { - log.error("Error validating cert against keystore: {}", scvEx.getMessage()); - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: invalid certificate path."); - } - break; - } - } catch (IOException ioEx) { - log.error("Error getting X509 cert from manager: {}", ioEx.getMessage()); - } - } - - for (SwidResource swidRes : resources) { - supportReferenceManifest = referenceManifestRepository.findByHexDecHashAndRimType( - swidRes.getHashValue(), ReferenceManifest.SUPPORT_RIM); - if (supportReferenceManifest != null) { - // Removed the filename check from this if statement - referenceManifestValidator.validateSupportRimHash( - supportReferenceManifest.getRimBytes(), swidRes.getHashValue()); - } - } - - if (passed && signingCert == null) { - passed = false; - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: signing cert not found."); - } - - if (passed && supportReferenceManifest == null) { - fwStatus = new AppraisalStatus(FAIL, - "Support Reference Integrity Manifest can not be found"); - passed = false; - } - - if (passed && !referenceManifestValidator.isSignatureValid()) { - passed = false; - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: Signature validation " - + "failed for Base RIM."); - } - - if (passed && !referenceManifestValidator.isSupportRimValid()) { - passed = false; - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: Hash validation " - + "failed for Support RIM."); - } - - if (passed) { - TCGEventLog expectedEventLog; - try { - expectedEventLog = new TCGEventLog(supportReferenceManifest.getRimBytes()); - baseline = expectedEventLog.getExpectedPCRValues(); - } catch (CertificateException | IOException | NoSuchAlgorithmException cEx) { - log.error(cEx); - } - - // part 1 of firmware validation check: PCR baseline match - pcrValidator = new PcrValidator(baseline); - - if (baseline.length > 0) { - String pcrContent = ""; - pcrContent = new String(device.getDeviceInfo().getTpmInfo().getPcrValues(), - StandardCharsets.UTF_8); - - if (pcrContent.isEmpty()) { - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: Client did not " - + "provide pcr values."); - log.warn("Firmware validation failed: Client ({}) did not " - + "provide pcr values.", device.getName()); - } else { - // we have a full set of PCR values - //int algorithmLength = baseline[0].length(); - //String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength); - //pcrPolicy.validatePcrs(storedPcrs); - - // part 2 of firmware validation check: bios measurements - // vs baseline tcg event log - // find the measurement - TCGEventLog actualEventLog; - LinkedList failedPcrValues = new LinkedList<>(); - List rimIntegrityMeasurements; - HashMap expectedEventLogRecords = new HashMap<>(); - try { - if (measurement.getDeviceName().equals(hostName)) { - actualEventLog = new TCGEventLog(measurement.getRimBytes()); - rimIntegrityMeasurements = referenceDigestValueRepository - .findValuesByBaseRimId(baseReferenceManifest.getId()); - for (ReferenceDigestValue rdv : rimIntegrityMeasurements) { - expectedEventLogRecords.put(rdv.getDigestValue(), rdv); - } - - failedPcrValues.addAll(pcrValidator.validateTpmEvents( - actualEventLog, expectedEventLogRecords, policySettings)); - } - } catch (CertificateException | NoSuchAlgorithmException | IOException exception) { - log.error(exception); - } - - if (!failedPcrValues.isEmpty()) { - StringBuilder sb = new StringBuilder(); - sb.append(String.format("%d digest(s) were not found:%n", - failedPcrValues.size())); - for (TpmPcrEvent tpe : failedPcrValues) { - sb.append(String.format("PCR Index %d - %s%n", - tpe.getPcrIndex(), - tpe.getEventTypeStr())); - } - if (fwStatus.getAppStatus().equals(FAIL)) { - fwStatus = new AppraisalStatus(FAIL, String.format("%s%n%s", - fwStatus.getMessage(), sb)); - } else { - fwStatus = new AppraisalStatus(FAIL, - sb.toString(), ReferenceManifest.MEASUREMENT_RIM); - } - } - } + AppraisalStatus rimSignatureStatus = validateRimSignature(baseReferenceManifest, + caCredentialRepository, referenceManifestRepository); + if (rimSignatureStatus.getAppStatus() == PASS) { + AppraisalStatus pcrStatus = validatePcrValues(device, hostName, baseReferenceManifest, + measurement, referenceDigestValueRepository, policySettings); + if (pcrStatus.getAppStatus() == PASS) { + EventLogMeasurements eventLog = measurement; + eventLog.setOverallValidationResult(PASS); + referenceManifestRepository.save(eventLog); + fwStatus = new AppraisalStatus(PASS, SupplyChainCredentialValidator.FIRMWARE_VALID); } else { - fwStatus = new AppraisalStatus(FAIL, "The RIM baseline could not be found."); + passed = false; } + } else { + passed = false; } - - EventLogMeasurements eventLog = measurement; - eventLog.setOverallValidationResult(fwStatus.getAppStatus()); - referenceManifestRepository.save(eventLog); - } else { + } + if (!passed) { fwStatus = new AppraisalStatus(FAIL, String.format("Firmware Validation failed: " + "%s for %s can not be found", failedString, hostName)); if (measurement != null) { @@ -291,7 +128,205 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { referenceManifestRepository.save(measurement); } } - return fwStatus; } + + private static AppraisalStatus validateRimSignature( + final BaseReferenceManifest baseReferenceManifest, + final CACredentialRepository caCredentialRepository, + final ReferenceManifestRepository referenceManifestRepository) { + List resources = + baseReferenceManifest.getFileResources(); + AppraisalStatus rimSignatureStatus = new AppraisalStatus(PASS, "RIM signature valid."); + boolean passed = true; + + // verify signatures + ReferenceManifestValidator referenceManifestValidator = + new ReferenceManifestValidator(); + referenceManifestValidator.setRim(baseReferenceManifest.getRimBytes()); + + //Validate signing cert + List allCerts = caCredentialRepository.findAll(); + CertificateAuthorityCredential signingCert = null; + for (CertificateAuthorityCredential cert : allCerts) { + signingCert = cert; + KeyStore keyStore = null; + Set set = ValidationService.getCaChainRec(signingCert, + Collections.emptySet(), + caCredentialRepository); + try { + keyStore = ValidationService.caCertSetToKeystore(set); + } catch (Exception e) { + log.error("Error building CA chain for " + signingCert.getSubjectKeyIdentifier() + ": " + + e.getMessage()); + } + + ArrayList certs = new ArrayList<>(set.size()); + for (CertificateAuthorityCredential cac : set) { + try { + certs.add(cac.getX509Certificate()); + } catch (IOException e) { + log.error( + "Error building CA chain for " + signingCert.getSubjectKeyIdentifier() + ": " + + e.getMessage()); + } + } + referenceManifestValidator.setTrustStore(certs); + try { + if (referenceManifestValidator.validateXmlSignature( + signingCert.getX509Certificate().getPublicKey(), + signingCert.getSubjectKeyIdString(), signingCert.getEncodedPublicKey())) { + try { + if (!SupplyChainCredentialValidator.verifyCertificate( + signingCert.getX509Certificate(), keyStore)) { + passed = false; + rimSignatureStatus = new AppraisalStatus(FAIL, + "RIM signature validation failed: invalid certificate path."); + } + } catch (IOException ioEx) { + log.error("Error getting X509 cert from manager: " + ioEx.getMessage()); + } catch (SupplyChainValidatorException scvEx) { + log.error("Error validating cert against keystore: " + scvEx.getMessage()); + rimSignatureStatus = new AppraisalStatus(FAIL, + "RIM signature validation failed: invalid certificate path."); + } + break; + } + } catch (IOException ioEx) { + log.error("Error getting X509 cert from manager: " + ioEx.getMessage()); + } + } + + for (SwidResource swidRes : resources) { + supportReferenceManifest = referenceManifestRepository.findByHexDecHashAndRimType( + swidRes.getHashValue(), ReferenceManifest.SUPPORT_RIM); + if (supportReferenceManifest != null) { + // Removed the filename check from this if statement + referenceManifestValidator.validateSupportRimHash( + supportReferenceManifest.getRimBytes(), swidRes.getHashValue()); + } + } + + if (passed && signingCert == null) { + passed = false; + rimSignatureStatus = new AppraisalStatus(FAIL, + "RIM signature validation failed: signing cert not found."); + } + + if (passed && supportReferenceManifest == null) { + rimSignatureStatus = new AppraisalStatus(FAIL, + "Support Reference Integrity Manifest can not be found"); + passed = false; + } + + if (passed && !referenceManifestValidator.isSignatureValid()) { + passed = false; + rimSignatureStatus = new AppraisalStatus(FAIL, + "RIM signature validation failed: Signature validation " + + "failed for Base RIM."); + } + + if (passed && !referenceManifestValidator.isSupportRimValid()) { + rimSignatureStatus = new AppraisalStatus(FAIL, + "RIM signature validation failed: Hash validation " + + "failed for Support RIM."); + } + + return rimSignatureStatus; + } + + private static AppraisalStatus validatePcrValues( + final Device device, + final String hostName, + final ReferenceManifest baseReferenceManifest, + final EventLogMeasurements measurement, + final ReferenceDigestValueRepository referenceDigestValueRepository, + final PolicySettings policySettings) { + + String[] baseline = new String[Integer.SIZE]; + TCGEventLog logProcessor; + AppraisalStatus pcrAppraisalStatus = new AppraisalStatus(PASS, "PCR values validated."); + try { + logProcessor = new TCGEventLog(supportReferenceManifest.getRimBytes()); + baseline = logProcessor.getExpectedPCRValues(); + } catch (CertificateException cEx) { + log.error(cEx); + } catch (NoSuchAlgorithmException noSaEx) { + log.error(noSaEx); + } catch (IOException ioEx) { + log.error(ioEx); + } + + // part 1 of firmware validation check: PCR baseline match + pcrValidator = new PcrValidator(baseline); + + if (baseline.length > 0) { + String pcrContent = ""; + pcrContent = new String(device.getDeviceInfo().getTpmInfo().getPcrValues(), + StandardCharsets.UTF_8); + + if (pcrContent.isEmpty()) { + pcrAppraisalStatus = new AppraisalStatus(FAIL, + "Firmware validation failed: Client did not " + + "provide pcr values."); + log.warn(String.format( + "Firmware validation failed: Client (%s) did not " + + "provide pcr values.", device.getName())); + } else { + // we have a full set of PCR values + //int algorithmLength = baseline[0].length(); + //String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength); + //pcrPolicy.validatePcrs(storedPcrs); + + // part 2 of firmware validation check: bios measurements + // vs baseline tcg event log + // find the measurement + TCGEventLog tcgMeasurementLog; + LinkedList tpmPcrEvents = new LinkedList<>(); + List eventValue; + HashMap eventValueMap = new HashMap<>(); + try { + if (measurement.getDeviceName().equals(hostName)) { + tcgMeasurementLog = new TCGEventLog(measurement.getRimBytes()); + eventValue = referenceDigestValueRepository + .findValuesByBaseRimId(baseReferenceManifest.getId()); + for (ReferenceDigestValue rdv : eventValue) { + eventValueMap.put(rdv.getDigestValue(), rdv); + } + + tpmPcrEvents.addAll(pcrValidator.validateTpmEvents( + tcgMeasurementLog, eventValueMap, policySettings)); + } + } catch (NoSuchAlgorithmException e) { + log.error(e); + } catch (CertificateException cEx) { + log.error(cEx); + } catch (IOException e) { + log.error(e); + } + + if (!tpmPcrEvents.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("%d digest(s) were not found:%n", + tpmPcrEvents.size())); + for (TpmPcrEvent tpe : tpmPcrEvents) { + sb.append(String.format("PCR Index %d - %s%n", + tpe.getPcrIndex(), + tpe.getEventTypeStr())); + } + if (pcrAppraisalStatus.getAppStatus().equals(FAIL)) { + pcrAppraisalStatus = new AppraisalStatus(FAIL, String.format("%s%n%s", + pcrAppraisalStatus.getMessage(), sb.toString())); + } else { + pcrAppraisalStatus = new AppraisalStatus(FAIL, + sb.toString(), ReferenceManifest.MEASUREMENT_RIM); + } + } + } + } else { + pcrAppraisalStatus = new AppraisalStatus(FAIL, "The RIM baseline could not be found."); + } + + return pcrAppraisalStatus; + } } From 7d950ea09c73ded0801dfe1c065a848119ef1cdc Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:36:49 -0500 Subject: [PATCH 6/9] Print error messages to log and ACA frontend --- .../persist/validation/FirmwareScvValidator.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java index c7ac85ec..8fb45ed8 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java @@ -59,6 +59,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { String hostName = device.getDeviceInfo().getNetworkInfo().getHostname(); BaseReferenceManifest baseReferenceManifest = null; EventLogMeasurements measurement = null; + log.info("Validating firmware..."); // This block was looking for a base RIM matching the device name // The base rim might not have a device name associated with it- i.e. if it's uploaded to the ACA @@ -114,15 +115,19 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { referenceManifestRepository.save(eventLog); fwStatus = new AppraisalStatus(PASS, SupplyChainCredentialValidator.FIRMWARE_VALID); } else { + failedString = pcrStatus.getMessage(); + log.warn("PCR value validation failed: " + failedString); passed = false; } } else { + failedString = rimSignatureStatus.getMessage(); + log.warn("RIM signature validation failed: " + failedString); passed = false; } } if (!passed) { fwStatus = new AppraisalStatus(FAIL, String.format("Firmware Validation failed: " - + "%s for %s can not be found", failedString, hostName)); + + "%s for %s cannot be found", failedString, hostName)); if (measurement != null) { measurement.setOverallValidationResult(fwStatus.getAppStatus()); referenceManifestRepository.save(measurement); @@ -139,6 +144,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { baseReferenceManifest.getFileResources(); AppraisalStatus rimSignatureStatus = new AppraisalStatus(PASS, "RIM signature valid."); boolean passed = true; + log.info("Validating RIM signature..."); // verify signatures ReferenceManifestValidator referenceManifestValidator = @@ -246,6 +252,8 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { String[] baseline = new String[Integer.SIZE]; TCGEventLog logProcessor; AppraisalStatus pcrAppraisalStatus = new AppraisalStatus(PASS, "PCR values validated."); + log.info("Validating PCR values..."); + try { logProcessor = new TCGEventLog(supportReferenceManifest.getRimBytes()); baseline = logProcessor.getExpectedPCRValues(); From 8484a829e010422a3cf97f8f9d83b2fa968bd15c Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Wed, 22 Jan 2025 01:40:04 -0500 Subject: [PATCH 7/9] Clean up error reporting and logging --- .../persist/validation/FirmwareScvValidator.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java index 8fb45ed8..2b4d6024 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java @@ -86,7 +86,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { String failedString = ""; if (baseReferenceManifest == null) { - failedString = "Base Reference Integrity Manifest\n"; + failedString = "Base Reference Integrity Manifest not found for " + hostName + "\n"; passed = false; } else if (measurement == null) { measurement = (EventLogMeasurements) referenceManifestRepository.findByHexDecHashAndRimType( @@ -99,7 +99,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { } if (measurement == null) { - failedString += "Bios measurement"; + failedString += "Bios measurement not found for " + hostName; passed = false; } @@ -126,8 +126,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { } } if (!passed) { - fwStatus = new AppraisalStatus(FAIL, String.format("Firmware Validation failed: " - + "%s for %s cannot be found", failedString, hostName)); + fwStatus = new AppraisalStatus(FAIL, failedString); if (measurement != null) { measurement.setOverallValidationResult(fwStatus.getAppStatus()); referenceManifestRepository.save(measurement); @@ -337,4 +336,9 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { return pcrAppraisalStatus; } + + private static void logAndReportError(AppraisalStatus status, String errorString) { + status.setMessage(errorString); + log.error(errorString); + } } From 9ee23b6249f92129f350aea80ee961b2d0b0136f Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Thu, 13 Feb 2025 09:49:33 -0500 Subject: [PATCH 8/9] Preserve messaging through AppraisalStatus object so that PCR mismatches display properly --- .../attestationca/persist/validation/FirmwareScvValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java index 2b4d6024..b32e9f67 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java @@ -106,9 +106,11 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { if (passed) { AppraisalStatus rimSignatureStatus = validateRimSignature(baseReferenceManifest, caCredentialRepository, referenceManifestRepository); + fwStatus = rimSignatureStatus; if (rimSignatureStatus.getAppStatus() == PASS) { AppraisalStatus pcrStatus = validatePcrValues(device, hostName, baseReferenceManifest, measurement, referenceDigestValueRepository, policySettings); + fwStatus = pcrStatus; if (pcrStatus.getAppStatus() == PASS) { EventLogMeasurements eventLog = measurement; eventLog.setOverallValidationResult(PASS); @@ -126,7 +128,6 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { } } if (!passed) { - fwStatus = new AppraisalStatus(FAIL, failedString); if (measurement != null) { measurement.setOverallValidationResult(fwStatus.getAppStatus()); referenceManifestRepository.save(measurement); From b418c814fce932eba65e5d74072c0e34c0b0658b Mon Sep 17 00:00:00 2001 From: chubtub <43381989+chubtub@users.noreply.github.com> Date: Thu, 13 Feb 2025 10:10:26 -0500 Subject: [PATCH 9/9] Checkstyle changes --- .../attestationca/persist/validation/FirmwareScvValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java index b32e9f67..fd962f26 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/validation/FirmwareScvValidator.java @@ -338,7 +338,7 @@ public class FirmwareScvValidator extends SupplyChainCredentialValidator { return pcrAppraisalStatus; } - private static void logAndReportError(AppraisalStatus status, String errorString) { + private static void logAndReportError(final AppraisalStatus status, final String errorString) { status.setMessage(errorString); log.error(errorString); }