{"id":22006359,"url":"https://github.com/a-sit-plus/warden-roboto","last_synced_at":"2025-05-05T22:34:53.909Z","repository":{"id":154171981,"uuid":"629547367","full_name":"a-sit-plus/warden-roboto","owner":"a-sit-plus","description":"Server-Side Android Attestation Library","archived":false,"fork":false,"pushed_at":"2025-04-29T20:52:44.000Z","size":329,"stargazers_count":9,"open_issues_count":3,"forks_count":3,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-29T21:37:17.882Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://a-sit-plus.github.io/warden-roboto/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/a-sit-plus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-04-18T14:29:59.000Z","updated_at":"2025-02-17T16:14:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"80e45e2d-e434-4c9e-9ed0-7482679aa551","html_url":"https://github.com/a-sit-plus/warden-roboto","commit_stats":null,"previous_names":["a-sit-plus/warden-roboto"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-sit-plus%2Fwarden-roboto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-sit-plus%2Fwarden-roboto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-sit-plus%2Fwarden-roboto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-sit-plus%2Fwarden-roboto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/a-sit-plus","download_url":"https://codeload.github.com/a-sit-plus/warden-roboto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252586782,"owners_count":21772352,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-30T01:11:45.196Z","updated_at":"2025-05-05T22:34:53.902Z","avatar_url":"https://github.com/a-sit-plus.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n![WARDEN-roboto](warden-roboto.png)\n\n# Server-Side Android Attestation Library\n\n[![A-SIT Plus Official](https://img.shields.io/badge/A--SIT_Plus-official-005b79?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNDMuNzYyODYgMTg0LjgxOTk5Ij48ZGVmcz48Y2xpcFBhdGggaWQ9ImEiIGNsaXBQYXRoVW5pdHM9InVzZXJTcGFjZU9uVXNlIj48cGF0aCBkPSJNMCA1OTUuMjhoODQxLjg5VjBIMFoiLz48L2NsaXBQYXRoPjwvZGVmcz48ZyBjbGlwLXBhdGg9InVybCgjYSkiIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMyAwIDAgLTEuMzMzMzMzMyAtNDgyLjI1IDUxNy41MykiPjxwYXRoIGZpbGw9IiMwMDViNzkiIGQ9Ik00MTUuNjcgMjQ5LjUzYy03LjE1LjA4LTEzLjk0IDEtMjAuMTcgMi43NWE1Mi4zMyA1Mi4zMyAwIDAgMC0xNy40OCA4LjQ2IDQwLjQzIDQwLjQzIDAgMCAwLTExLjk2IDE0LjU2Yy0yLjY4IDUuNDEtNC4xNCAxMS44NC00LjM1IDE5LjA5bC0uMDIgNi4xMnYyLjE3YS43MS43MSAwIDAgMCAuNy43M2gxNi41MmMuMzkgMCAuNy0uMzIuNzEtLjdsLjAxLTIuMmMwLTIuNi4wMi01LjgyLjAzLTYuMDcuMi00LjYgMS4yNC04LjY2IDMuMDgtMTIuMDZhMjguNTIgMjguNTIgMCAwIDEgOC4yMy05LjU4IDM1LjI1IDM1LjI1IDAgMCAxIDExLjk2LTUuNTggNTUuMzggNTUuMzggMCAwIDEgMTIuNTgtMS43NmM0LjMyLjEgOC42LjcgMTIuNzQgMS44YTM1LjA3IDM1LjA3IDAgMCAxIDExLjk2IDUuNTcgMjguNTQgMjguNTQgMCAwIDEgOC4yNCA5LjU3YzEuOTYgMy42NCAzIDguMDIgMy4xMiAxMy4wMnYyNC4wOUgzNjIuNGEuNy43IDAgMCAwLS43MS43VjMzNWMwIDguNDMuMDEgOC4wNS4wMSA4LjE0LjIgNy4zIDEuNjcgMTMuNzcgNC4zNiAxOS4yMmE0MC40MyA0MC40MyAwIDAgMCAxMS45NiAxNC41N2M1IDMuNzYgMTAuODcgNi42MSAxNy40OCA4LjQ2YTc3LjUgNzcuNSAwIDAgMCAyMC4wMiAyLjc3YzcuMTUtLjA3IDEzLjk0LTEgMjAuMTctMi43NGE1Mi4zIDUyLjMgMCAwIDAgMTcuNDgtOC40NiA0MC40IDQwLjQgMCAwIDAgMTEuOTUtMTQuNTdjMS42Mi0zLjI2IDMuNzctMTAuMDQgMy43Ny0xNC42OCAwLS4zOC0uMTctLjc0LS41NC0uODJsLTE2Ljg5LS40Yy0uMi0uMDQtLjM0LjM0LS4zNC41NCAwIC4yNy0uMDMuNC0uMDYuNi0uNSAyLjgyLTEuMzggNS40LTIuNjEgNy42OWEyOC41MyAyOC41MyAwIDAgMS04LjI0IDkuNTggMzUuMDEgMzUuMDEgMCAwIDEtMTEuOTYgNS41NyA1NS4yNSA1NS4yNSAwIDAgMS0xMi41NyAxLjc3Yy00LjMyLS4xLTguNjEtLjcxLTEyLjc1LTEuOGEzNS4wNSAzNS4wNSAwIDAgMS0xMS45Ni01LjU3IDI4LjUyIDI4LjUyIDAgMCAxLTguMjMtOS41OGMtMS44Ni0zLjQ0LTIuOS03LjU1LTMuMDktMTIuMmwtLjAxLTcuNDdoODkuMTZhLjcuNyAwIDAgMCAuNy0uNzJ2LTM5LjVjLS4xLTcuNjUtMS41OC0xNC40LTQuMzgtMjAuMDZhNDAuNCA0MC40IDAgMCAwLTExLjk1LTE0LjU2IDUyLjM3IDUyLjM3IDAgMCAwLTE3LjQ4LTguNDcgNzcuNTYgNzcuNTYgMCAwIDAtMjAuMDEtMi43N1oiLz48cGF0aCBmaWxsPSIjY2U0OTJlIiBkPSJNNDE5LjM4IDI4MC42M2gtNy41N2EuNy43IDAgMCAwLS43MS43MXYxNS40MmE4LjE3IDguMTcgMCAwIDAtMy43OCA2LjkgOC4yOCA4LjI4IDAgMCAwIDE2LjU0IDAgOC4yOSA4LjI5IDAgMCAwLTMuNzYtNi45di0xNS40MmEuNy43IDAgMCAwLS43Mi0uNzEiLz48L2c%2BPC9zdmc%2B\u0026logoColor=white\u0026labelColor=white)](https://a-sit-plus.github.io)\n[![GitHub license](https://img.shields.io/badge/license-Apache%20License%202.0-brightgreen.svg?style=flat)](http://www.apache.org/licenses/LICENSE-2.0) \n[![Kotlin](https://img.shields.io/badge/kotlin-2.0.0-blue.svg?logo=kotlin)](http://kotlinlang.org)\n![Java](https://img.shields.io/badge/java-17-blue.svg?logo=OPENJDK)\n![Build artifacts](https://github.com/a-sit-plus/warden-roboto/actions/workflows/gradle-build.yml/badge.svg)\n[![Maven Central](https://img.shields.io/maven-central/v/at.asitplus/warden-roboto)](https://mvnrepository.com/artifact/at.asitplus/warden-roboto/)\n\n\u003c/div\u003e\n\nThis Kotlin library provides a convenient API (a single function, actually) to remotely attest the integrity of an Android device, its OS, and a specific application.\nIt is intended to be integrated into back-end services requiring authentic, unmodified mobile clients (but it also works in other settings, such as peer-to-peer-scenarios).\n\nFull API docs are available [here](https://a-sit-plus.github.io/warden-roboto).\n\nThis library's core logic is based off [code from Google](https://github.com/google/android-key-attestation) (and actually directly integrates it), such that it can easily keep up with upstream for the lower-level functionality.\nBecause of this, it only targets the JVM, although a KMP rewrite (also targeting JS/Node) is possible.\nThis JVM-centricity is also the reason why the function signatures are rather JVM-esque (read: exceptions are thrown on error,\nas done by pretty much every verification function of classes form the `java.security` package).\n\nThis library is an integral part of the more comprehensive [WARDEN](https://github.com/a-sit-plus/warden) server-side mobile client attestation library, which also supports iOS clients and provides\nmore idiomatic kotlin interfaces.\nHowever, if you are only concerned about Android clients, this library provides all functionality needed without unnecessary bloat.\n\nAnother useful feature of this library is the possibility to set custom trust anchors and thus use automatically generated 'fake' attestations\nfor end-to-end-tests, for example.\n\n## Development\n\nSee [DEVELOPMENT.md](https://github.com/a-sit-plus/warden-roboto/blob/main/DEVELOPMENT.md)\n\n## Background\nAndroid devices with a TEE allow for cryptographic keys to be generated in hardware. These keys can only be used, but not exported and are safe from extraction due protective hardware measures. The Android Keystore API expose this hardware-based management of cryptographic material and also allows for generating certficates for such keys, which contain custom Extension that indicate the location of a key (hardware or software).\n\u003cbr\u003e\nAdditional extension (populated by the cryptographic hardware during key generation) further indicate the device's integrity state (bootloader unlocked, system image integrity, …). This certificate is signed in hardware by a manufacturer key (also protected by hardware) which is provisioned during device manufacturing. A certificate corresponding to this manufacurer key is signed by Google, and the public key of this signing key is published by Google.\nHence, verifying this certificate chain against this Google root key makes it possible to assert the authenticity of the leaf certificate. Checking the custom extension of this leaf certificate consequently allows for remotely establishing trust in an Android device and the application which created the underlying key.\nA noteworthy property of this attestation concept is that no third party needs to be contacted (except for obtaining certificate revocation information) compared to Apple's AppAttest/DeviceCheck.\n\n## Usage\n\nWritten in Kotlin, plays nicely with Java (cf. `@JvmOverloads`), published at maven central.\n### Gradle\n\n```kotlin\n dependencies {\n     implementation(\"at.asitplus:warden-roboto:$version\")\n }\n```\n\nThree flavours of attestation are implemented:\n* Hardware attestation through [HardwareAttestationChecker](https://github.com/a-sit-plus/warden-roboto/blob/main/warden-roboto/src/main/kotlin/AndroidAttestationChecker.kt)\n  (this is what you typically want)\n* Software attestation through [SoftwareAttestationChecker](https://github.com/a-sit-plus/warden-roboto/blob/main/warden-roboto/src/main/kotlin/SoftwareAttestationChecker.kt)\n  (you typically don't want to use this)\n* Nougat hybrid attestation through [NougatHybridAttestationChecker](https://github.com/a-sit-plus/warden-roboto/blob/main/warden-roboto/src/main/kotlin/NougatHybridAttestationChecker.kt)\n  (you may require this to support legacy devices originally shipped with Android 7 (Nougat)). Does **NOT** support checking:\n    * Verified boot state and system image integrity\n    * Android version\n    * Attestation statement creation time\n\nAll of these extend [AndroidAttestationChecker](https://github.com/a-sit-plus/warden-roboto/blob/main/warden-roboto/src/main/kotlin/AndroidAttestationChecker.kt)\n\n\n### Configuration\nConfiguration is based on the data class `AttestationConfiguration`. Some properties are nullable – if unset, no checks against these properties are made.\n\n**Note:** In order to use anything but the `HardwareAttestationChecker` the corresponding flags need to be set in the configuration.\nThis serves a dual purpose:\n1. It makes shooting yourself in the foot a lot harder (i.e. accidentally enabling software attestation or disabling\n   hardware attestation requires more manual effort).\n2. It allows for instantiating AttestationCheckers based on these flags, for example, when chaining hardware attestation\n   with nougat-style attestation as a fallback just from evaluating an `AndroidAttestationConfiguration` instance.\n\nWhen using Kotlin, named parameters make configuration straight-forward: \n\n```kotlin\nAndroidAttestationConfiguration(\n    applications= listOf(   //REQUIRED: add applications to be attested\n        AndroidAttestationConfiguration.AppData(\n            packageName = \"at.asitplus.attestation_client\",\n            signatureDigests = listOf(\"NLl2LE1skNSEMZQMV73nMUJYsmQg7=\".encodeToByteArray()),\n            appVersion = 5\n        ),\n        AndroidAttestationConfiguration.AppData( //we have a dedicated app for latest android version\n            packageName = \"at.asitplus.attestation_client-tiramisu\",\n            signatureDigests = listOf(\"NLl2LE1skNSEMZQMV73nMUJYsmQg7=\".encodeToByteArray()),\n            appVersion = 2, //with a different versioning scheme\n            androidVersionOverride = 130000, //so we need to override this\n            patchLevelOverride = PatchLevel(2023, 6) //also override patch level\n        )\n    ),\n    androidVersion = 110000,                //OPTIONAL, null by default\n    patchLevel = PatchLevel(2022, 12),      //OPTIONAL, null by default\n    requireStrongBox = false,               //OPTIONAL, defaults to false\n    allowBootloaderUnlock = false,          //OPTIONAL, defaults to false\n    requireRollbackResistance = false,      //OPTIONAL, defaults to false\n    ignoreLeafValidity = false,             //OPTIONAL, defaults to false\n    hardwareAttestationTrustAnchors = linkedSetOf(*DEFAULT_HARDWARE_TRUST_ANCHORS), //OPTIONAL, defaults  shown here\n    softwareAttestationTrustAnchors = linkedSetOf(*DEFAULT_SOFTWARE_TRUST_ANCHORS), //OPTIONAL, defaults  shown here\n    verificationSecondsOffset = -300,       //OPTIONAL, defaults to 0\n    attestationStatementValiditySeconds = 0,//OPTIONAL, defaults to 300. Affects timestamp checks against the attestation statement creation, not the certificate.\n    disableHardwareAttestation = false,     //OPTIONAL, defaults to false\n    enableNougatAttestation = false,        //OPTIONAL, defaults to false\n    enableSoftwareAttestation = false,      //OPTIONAL, defaults to false\n    httpProxy = null                        //OPTIONAL HTTP proxy url, such as http://proxy.domain:12345, defaults to null for no proxy\n)\n```\n\nAdditionally, a builder is available for smoother java interoperability:\n\n```java\nList\u003cAndroidAttestationConfiguration.AppData\u003e apps = new LinkedList\u003c\u003e();\n\napps.add(new AndroidAttestationConfiguration.AppData(\n        \"at.asitplus.example\",\n        Collections.singletonList(Base64.getDecoder().decode(\"NLl2LE1skNSEMZQMV73nMUJYsmQg7+Fqx/cnTw0zCtU=\"))\n));\napps.add(new AndroidAttestationConfiguration.AppData(\n        \"at.asitplus.anotherexample\",\n        Collections.singletonList(Base64.getDecoder().decode(\"NLl2LE1skNSEMZQMV73nMUJYsmQg7+Fqx/cnTw0zCtU=\")),\n        2\n));\nAndroidAttestationConfiguration config = new AndroidAttestationConfiguration.Builder(apps)\n        .androidVersion(110000)\n        .ingoreLeafValidity()\n        .patchLevel(new PatchLevel(2023, 03))\n        .verificationSecondsOffset(-500) //we to account for time drift\n        .build();\n```\n\nThe (nullable) properties like patch level and app version essentially allow for excluding outdated devices and obsolete app releases. If, for example a critical flaw is discovered in an attested app, users can be forced to update by considering only the latest and greatest version trustworthy and configuring the `AndroidAttestationChecker` instance accordingly.\n\nIn addition to configuration, it is possible to override the function which verifies the challenge used to verify an attestation when instantiating an `\u003c*\u003eAttestationChecker`\nBy default, this is simply a `contentEquals` on the provided challenge vs a reference value.\n\n### Obtaining an Attestation Result\n1. The general workflow this library caters to assumes a back-end service, sending an attestation challenge to the mobile app. This challenge needs to be kept for future reference\n2. The app is assumed to generate a key pair with attestation (passing the received challenge the Android Keystore)\n3. The app responds with the certificate chain associated with this key pair\n4. On the back-end a single call to `AndroidAttestationChecker.verifyAttestation()` is sufficient to remotely verify the app's integrity and establish trust in the app. This call requires the challenge from step 1.\n\n```kotlin\nval checker = HardwareAttestationChecker(config)\n\n//throws an exception if attestation fails, return a ParsedAttestationRecord on success, which can be inspected\nval attestationRecord =  checker.verifyAttestation(attestationCertChain, Date(), challengeFromStep1)\n```\n\n## Debugging\n\n### Recording and Replaying Attestation Checks\nSince WARDEN-roboto 1.8.0, `AndroidAttestationChecker` has a method to record the current config and an attestation statement to-be-checked:\n\n```kotlin\ncollectDebugInfo(\ncertificates: List\u003cX509Certificate\u003e,\nexpectedChallenge: ByteArray,\nverificationDate: Date = Date(),\n): AndroidDebugAttestationStatement\n```\n\nThe resulting class can be serialized to JSON by invoking `.serialize()` on it.\nIt can later be deserialized by calling `deserialize()` on its companion.\nBy finally calling `replay()` on the deserialized debug info object, an attestation verification is performed.\n\nAttaching a debugger allows for step-by-step debugging of any attestation errors encountered.\n\n### Printing Human-Readable Attestation Info\nThe module [attestation-diag](https://github.com/a-sit-plus/warden-roboto/blob/main/attestation-diag) contains a\n(very) simple command-line utility. It can be built using the `shadowJar` gradle task and pretty-prints attestation\ninformation contained in attestation certificates:\n```shell\njava -jar attestation-diag-0.0.3-all.jar \"MIICkDCCAjagAwIBAgIBATAKBggqhkjOPQQDAjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDE7MDkGA1UEAwwyQW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBJbnRlcm1lZGlhdGUwIBcNNzAwMTAxMDAwMDAwWhgPMjEwNjAyMDcwNjI4MTVaMB8xHTAbBgNVBAMMFEFuZHJvaWQgS2V5c3RvcmUgS2V5MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoX5eWkxsJOk2z6S5tclt6bOyJhS3b+2+ULx3O3zZAwFNrbWP52YnQzp\\/lsexI99lx\\/Z5NRzJ9x0aD\nLdIcR\\/AyqOB9jCB8zALBgNVHQ8EBAMCB4AwgcIGCisGAQQB1nkCAREEgbMwgbACAQIKAQACAQEKAQEEB2Zvb2JkYXIEADBev4U9BwIFAKtq1Vi\\/hUVPBE0wSzElMCMEHmNvbS5leGFtcGxlLnRydXN0ZWRhcHBsaWNhdGlvbgIBATEiBCCI5cOT6u82gpgAtB33hqUv8KWCFYUMqKZQc4Wa3PAZDzA3oQgxBgIBAgIBA6IDAgEDowQCAgEApQgxBgIBAAIBBKoDAgEBv4N3AgUAv4U+AwIBAL+FPwIFADAfBgNVHSMEGDAWgBQ\\/\\/KzWGrE6noEguNUlHMVlux6RqTAKBggqhkjOPQQDAgNIADBFAiBiMBtVeUV4j1VOiRU8DnGzq9\\/xtHfl0wra1xnsmxG+LAIhAJAroVhVcxxItgYZEMN1AaWqmZUXFtktQeLXh7u2F3d+\"\n```\n\nThe result from the above call is a pretty-printed JSON:\n```json\n{\n  \"attestationVersion\": 2,\n  \"attestationSecurityLevel\": \"SOFTWARE\",\n  \"keymasterVersion\": 1,\n  \"keymasterSecurityLevel\": \"TRUSTED_ENVIRONMENT\",\n  \"attestationChallenge\": \"666F6F62646172\",\n  \"uniqueId\": \"\",\n  \"softwareEnforced\": {\n    \"rollbackResistance\": false,\n    \"noAuthRequired\": false,\n    \"allowWhileOnBody\": false,\n    \"trustedUserPresenceRequired\": false,\n    \"trustedConfirmationRequired\": false,\n    \"unlockedDeviceRequired\": false,\n    \"allApplications\": false,\n    \"creationDateTime\": \"1970-02-03T06:51:45.368Z\",\n    \"rollbackResistant\": false,\n    \"attestationApplicationId\": {\n      \"packageInfos\": [\n        {\n          \"packageName\": \"com.example.trustedapplication\",\n          \"version\": 1\n        }\n      ],\n      \"signatureDigests\": [\n        \"88E5C393EAEF36829800B41DF786A52FF0A58215850CA8A65073859ADCF0190F\"\n      ]\n    },\n    \"attestationApplicationIdBytes\": \"304B31253023041E636F6D2E6578616D706C652E747275737465646170706C69636174696F6E0201013122042088E5C393EAEF36829800B41DF786A52FF0A58215850CA8A65073859ADCF0190F\",\n    \"individualAttestation\": false,\n    \"identityCredentialKey\": false\n  },\n  \"teeEnforced\": {\n    \"purpose\": [\n      \"SIGN\",\n      \"VERIFY\"\n    ],\n    \"algorithm\": \"EC\",\n    \"keySize\": 256,\n    \"digest\": [\n      \"NONE\",\n      \"SHA_2_256\"\n    ],\n    \"ecCurve\": \"P_256\",\n    \"rollbackResistance\": false,\n    \"noAuthRequired\": true,\n    \"allowWhileOnBody\": false,\n    \"trustedUserPresenceRequired\": false,\n    \"trustedConfirmationRequired\": false,\n    \"unlockedDeviceRequired\": false,\n    \"allApplications\": false,\n    \"origin\": \"GENERATED\",\n    \"rollbackResistant\": true,\n    \"individualAttestation\": false,\n    \"identityCredentialKey\": false\n  },\n  \"attestedKey\": {\n    \"algorithm\": \"EC\",\n    \"format\": \"X.509\",\n    \"encoded\": \"3059301306072A8648CE3D020106082A8648CE3D03010703420004A17E5E5A4C6C24E936CFA4B9B5C96DE9B3B22614B76FEDBE50BC773B7CD903014DADB58FE76627433A7F96C7B123DF65C7F679351CC9F71D1A0CB748711FC0CA\"\n  }\n}\n\n```\n\nNulls and empty arrays are omitted by default, but can be printed by adding `-v` at the end of the command line.\nThe example below shows a verbose JSON obtained this way:\n```json\n{\n  \"attestationVersion\": 2,\n  \"attestationSecurityLevel\": \"SOFTWARE\",\n  \"keymasterVersion\": 1,\n  \"keymasterSecurityLevel\": \"TRUSTED_ENVIRONMENT\",\n  \"attestationChallenge\": \"666F6F62646172\",\n  \"uniqueId\": \"\",\n  \"softwareEnforced\": {\n    \"purpose\": [],\n    \"algorithm\": null,\n    \"keySize\": null,\n    \"digest\": [],\n    \"padding\": [],\n    \"ecCurve\": null,\n    \"rsaPublicExponent\": null,\n    \"rollbackResistance\": false,\n    \"activeDateTime\": null,\n    \"originationExpireDateTime\": null,\n    \"usageExpireDateTime\": null,\n    \"noAuthRequired\": false,\n    \"userAuthType\": [],\n    \"authTimeout\": null,\n    \"allowWhileOnBody\": false,\n    \"trustedUserPresenceRequired\": false,\n    \"trustedConfirmationRequired\": false,\n    \"unlockedDeviceRequired\": false,\n    \"allApplications\": false,\n    \"applicationId\": null,\n    \"creationDateTime\": \"1970-02-03T06:51:45.368Z\",\n    \"origin\": null,\n    \"rollbackResistant\": false,\n    \"rootOfTrust\": null,\n    \"osVersion\": null,\n    \"osPatchLevel\": null,\n    \"attestationApplicationId\": {\n      \"packageInfos\": [\n        {\n          \"packageName\": \"com.example.trustedapplication\",\n          \"version\": 1\n        }\n      ],\n      \"signatureDigests\": [\n        \"88E5C393EAEF36829800B41DF786A52FF0A58215850CA8A65073859ADCF0190F\"\n      ]\n    },\n    \"attestationApplicationIdBytes\": \"304B31253023041E636F6D2E6578616D706C652E747275737465646170706C69636174696F6E0201013122042088E5C393EAEF36829800B41DF786A52FF0A58215850CA8A65073859ADCF0190F\",\n    \"attestationIdBrand\": null,\n    \"attestationIdDevice\": null,\n    \"attestationIdProduct\": null,\n    \"attestationIdSerial\": null,\n    \"attestationIdImei\": null,\n    \"attestationIdSecondImei\": null,\n    \"attestationIdMeid\": null,\n    \"attestationIdManufacturer\": null,\n    \"attestationIdModel\": null,\n    \"vendorPatchLevel\": null,\n    \"bootPatchLevel\": null,\n    \"individualAttestation\": false,\n    \"identityCredentialKey\": false\n  },\n  \"teeEnforced\": {\n    \"purpose\": [\n      \"SIGN\",\n      \"VERIFY\"\n    ],\n    \"algorithm\": \"EC\",\n    \"keySize\": 256,\n    \"digest\": [\n      \"NONE\",\n      \"SHA_2_256\"\n    ],\n    \"padding\": [],\n    \"ecCurve\": \"P_256\",\n    \"rsaPublicExponent\": null,\n    \"rollbackResistance\": false,\n    \"activeDateTime\": null,\n    \"originationExpireDateTime\": null,\n    \"usageExpireDateTime\": null,\n    \"noAuthRequired\": true,\n    \"userAuthType\": [],\n    \"authTimeout\": null,\n    \"allowWhileOnBody\": false,\n    \"trustedUserPresenceRequired\": false,\n    \"trustedConfirmationRequired\": false,\n    \"unlockedDeviceRequired\": false,\n    \"allApplications\": false,\n    \"applicationId\": null,\n    \"creationDateTime\": null,\n    \"origin\": \"GENERATED\",\n    \"rollbackResistant\": true,\n    \"rootOfTrust\": null,\n    \"osVersion\": null,\n    \"osPatchLevel\": null,\n    \"attestationApplicationId\": null,\n    \"attestationApplicationIdBytes\": null,\n    \"attestationIdBrand\": null,\n    \"attestationIdDevice\": null,\n    \"attestationIdProduct\": null,\n    \"attestationIdSerial\": null,\n    \"attestationIdImei\": null,\n    \"attestationIdSecondImei\": null,\n    \"attestationIdMeid\": null,\n    \"attestationIdManufacturer\": null,\n    \"attestationIdModel\": null,\n    \"vendorPatchLevel\": null,\n    \"bootPatchLevel\": null,\n    \"individualAttestation\": false,\n    \"identityCredentialKey\": false\n  },\n  \"attestedKey\": {\n    \"algorithm\": \"EC\",\n    \"format\": \"X.509\",\n    \"encoded\": \"3059301306072A8648CE3D020106082A8648CE3D03010703420004A17E5E5A4C6C24E936CFA4B9B5C96DE9B3B22614B76FEDBE50BC773B7CD903014DADB58FE76627433A7F96C7B123DF65C7F679351CC9F71D1A0CB748711FC0CA\"\n  }\n}\n```\n\nAttestation certificates can also be read from a file (need to be PEM-encoded, but can also be plain base64 MIME-encoded):\n```shell\njava -jar attestation-diag-0.0.3-all.jar -f cert.pem\n```\n\n(Some) illegal characters are stripped from the base64 input for convenience, which means that dirty base64 also somewhat works.\n\n**Note:** Pretty-printing is done using Gson (in order to leave the upstream code untouched), which also means that it relies\non reflective access to platform types. Hence, this jar will only run on the same Java version it was built with!\n\n\n## Contributing\nExternal contributions are greatly appreciated!\nJust be sure to observe the contribution guidelines (see [CONTRIBUTING.md](CONTRIBUTING.md)).\n\n\n\u003cbr\u003e\n\n---\n\u003cp align=\"center\"\u003e\nThis project has received funding from the European Union’s Horizon 2020 research and innovation\nprogramme under grant agreement No 959072.\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"eu.svg\" alt=\"EU flag\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\nThe Apache License does not apply to the logos, (including the A-SIT logo) and the project/module name(s), as these are the sole property of\nA-SIT/A-SIT Plus GmbH and may not be used in derivative works without explicit permission!\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa-sit-plus%2Fwarden-roboto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fa-sit-plus%2Fwarden-roboto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa-sit-plus%2Fwarden-roboto/lists"}