iotaledger / identity.rs

Implementation of the Decentralized Identity standards such as DID and Verifiable Credentials by W3C for the IOTA Tangle.
https://www.iota.org
Apache License 2.0
298 stars 84 forks source link

[Task] `0.7` release tasks. #1103

Closed olivereanderson closed 9 months ago

olivereanderson commented 1 year ago

Description

At a high level these are the remaining tasks before 0.7 can be released.:

Motivation

Motivation for replacing JcsEd25519Signature2020 proofs with JWTs: Securing verifiable data with JWTs is desirable in order to align with established projects like EBSI . It also provides some amount of cryptographic agility to implementers in a relatively simple manner. Furthermore there are known issues with the JcsEd25519Signature2020 spec we are currently using (see #22 and #26).

Resources

Link to any resources relevant for the task such as issues, PRs, reference implementations, or specifications.

To-do list

Create a task-specific to-do list. Please link PRs that match the TODO list item behind the item after it has been submitted.

mighty840 commented 1 year ago

For consideration of embedded devices, the following should be kept in mind:

JWS/JWT uses canonicalization according to RFC-8785. This cannot be however implemented exactly on small embedded devices. Currently, for the ALFRIED project, the following canonicalization scheme is under use:

Canonicalization

Rationale

JSON documents are a representation of a data structure organized as a tree. A deterministic representation of the data structure is needed for cryptographic signature verification, since the representation at the time of generation and at the time of verification need to be the same.

Assumptions

It is assumed that the JSON document is a JSON object which only consists of JSON objects, array and/or strings. Strings a plain ASCII strings without control characters and without \.

Algorithm description

Example implementation in Python

json.dumps(did, sort_keys=True, separators=(',',':'));

This is an example of a signed DID:

Signed DIDs are generated by all participants besides the root DID and the intermediate CAs. The purpose of the DID documents is to distribute public keys. Each signed DID document is signed by its owner to prove authenticity an prevent intentional or accidental tempering of the document. There are three public keys. The private key for the authentication method is kept in a hardware module (ATECC608 IC). This module only support NIST P-256 cryptorgraphy. The other keys are managed in the microcontroller. The timestamp in the proof field is kept at a fixed value to prevent manufacturing data information leakage.


Example signed DID document:

{
    "assertionMethod": [
        {
            "controller": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC",
            "id": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC#assertion",
            "publicKeyJwk": {
                "crv": "Ed25519",
                "kty": "OKP",
                "x": "nm5qzIL0UMjYLBdvSj-MOjFHQ-qEq-osmJu2fELXsrY"
            },
            "type": "JsonWebKey2020"
        }
    ],
    "authentication": [
        {
            "controller": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC",
            "id": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC#authentication",
            "publicKeyJwk": {
                "crv": "P-256",
                "kty": "EC",
                "x": "WDd6GPpt1TBQy1t4fBKTzgucXlzIM07lDxBsG9Hfo8I",
                "y": "7GFdcNNms_psKT0P4p7eXqQatEV7FkJWU_oP3TpjFMs"
            },
            "type": "JsonWebKey2020"
        }
    ],
    "id": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC",
    "keyAgreement": [
        {
            "controller": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC",
            "id": "did:iota:Bz4HfuxzdEuuXkf66yDi2ytXehmVoLSBo9KnAEa2WExC#keyagreement",
            "publicKeyJwk": {
                "crv": "X25519",
                "kty": "OKP",
                "x": "qJ2jXc72DklDgNIabXDbFLmYOz7kvye39PQdQFAJeq8"
            },
            "type": "JsonWebKey2020"
        }
    ],
    "proof": {
        "created": "2000-01-01T00:00:00Z",
        "proofPurpose": "authentication",
        "signature": "ryxMNBGGRCNEgPIG-X_XkwRswjqdiwgX_Lus7K8pyw2daZg37EPZFpp7KYyX7VsBcrt9rZepGpC4_5SI9JKSxQ",
        "type": "SimpleSignature_ES256_2022",
        "verificationMethod": "#authentication"
    }
}

Verifiable Credentials (VCs)


Example intermediate VC document which can sign Firmware

{
    "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://some_other_configurable_URL"
    ],
    "credentialSubject": {
        "capabilities": {
            "canSign": [
                "Firmware"
            ]
        },
        "did": {
            "assertionMethod": [
                {
                    "controller": "did:iota:3CSYjMj8nf2XJMka5PduRpXB7GLoMRsM6kxG3KHLas4N",
                    "id": "did:iota:3CSYjMj8nf2XJMka5PduRpXB7GLoMRsM6kxG3KHLas4N#assertion",
                    "publicKeyJwk": {
                        "crv": "Ed25519",
                        "kty": "OKP",
                        "x": "1SpLqY1GFxi_G47aq_T9-ZcXD48WIvjXu_o5z_l23KQ"
                    },
                    "type": "JsonWebKey2020"
                }
            ],
            "id": "did:iota:3CSYjMj8nf2XJMka5PduRpXB7GLoMRsM6kxG3KHLas4N"
        }
    },
    "issuer": "did:iota:8G4dCsxH9qUQgDMp3wbwTfUMK4usWnAkjVudGJuk5LKG",
    "proof": {
        "created": "2022-01-01T00:00:00Z",
        "proofPurpose": "assertionMethod",
        "signature": "KD_cqoZAnhgM3Vr3nr7N7Th4xd0UgHuO5Uzy9hfSK7iv3c4ms_pi2oASJ6IYUqfjU_Mq4QHgjMIFqky4zwjzCw",
        "type": "SimpleSignature_EdDSA_2022",
        "verificationMethod": "did:iota:8G4dCsxH9qUQgDMp3wbwTfUMK4usWnAkjVudGJuk5LKG#assertion"
    },
    "type": [
        "VerifiableCredential",
        "ProvisioningServer"
    ],
    "validFrom": "2022-07-01T00:00:00Z",
    "validUntil": "2023-01-01T00:00:00Z"
}

The SimpleSignature_EdDSA_2022 and SimpleSignature_ES256_2022 are currently non-standard signature schemes used internally. However, in case if they are JWS/JCS then the canonicalization according to the RFC cannot be implemented on small embedded devices with bare-metal implementations.

PhilippGackstatter commented 1 year ago

Hello @mighty840,

thanks for reaching out.

JWS/JWT uses canonicalization according to RFC-8785.

As far as we're aware, JWS/JWT does not use canonicalization. RFC7519 states in Section 7.1 "Creating a JWT":

  1. Create a JWT Claims Set containing the desired claims. Note that whitespace is explicitly allowed in the representation and no canonicalization need be performed before encoding.

In light of this, can you clarify if there is any issue for you with JWS/JWT?

mighty840 commented 1 year ago

Hello @PhilippGackstatter

Before SimpleSignature_EdDSA_2022, we were using JsonWebSignature2020 algorithm. In there, the mentioned canonicalization algorithm was not usable on embedded devices. Hence, we changed it to the simple one as mentioned before and renamed the scheme.

When it comes to canonicalization in general, we need it in one form or another.

Any embedded device cannot have JSON Data representaion scheme available in itself. The individual values are arranged together byte-by-byte to form a serialized string, which is then used as payload to send to the crypto IC for generating the signature. This string can be de-serialized to represent a JSON object. Based on the implementation of the serialization and de-serialization methods, the byte-representation could change.

Moreover, during the verification, the exact same ordering of bytes is required to generate the hash for verifying signature. Hence, to securely verify signature, a knowledge of the ordering is needed, or every verifier and generator of signature is supplied with a standard ordering algorithm.

The JSON string being created and encoded in JWT without canonicalization is not a problem, however when it comes to generating a signature on the binary representation object, a deterministic method of ordering the JSON is a hard requirement, otherwise every participant may try to assume the order of JSON keys from the string encoding, which may or may not be the same order used for creating the digest for signature generation/verification.

I hope this helps to understand the rationale behind having one or other type of JSON ordering in place.

olivereanderson commented 1 year ago

Hello @mighty840, I would like to try to clarify some things from your last comment. There might be a misunderstanding (possibly on our side).

Before SimpleSignature_EdDSA_2022, we were using JsonWebSignature2020 algorithm. In there, the mentioned canonicalization algorithm was not usable on embedded devices.

Note that we are proposing to use VC-JWT not JsonWebSignature2020. We emphasize that these are rather different formats for securing verifiable data such as credentials or presentations.

The JSON string being created and encoded in JWT without canonicalization is not a problem, however when it comes to generating a signature on the binary representation object, a deterministic method of ordering the JSON is a hard requirement, otherwise every participant may try to assume the order of JSON keys from the string encoding, which may or may not be the same order used for creating the digest for signature generation/verification.

Why do participants need to assume the order of JSON keys? Suppose a verifier is given the following JWT (where for human parsing the header is typed with italics, the payload enclosed in " " and signature in bold):

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRpZDpleGFtcGxlOmFiZmUxM2Y3MTIxMjA0 MzFjMjc2ZTEyZWNhYiNrZXlzLTEifQ.eyJzdWIiOiJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxY zI3NmUxMmVjMjEiLCJqdGkiOiJodHRwOi8vZXhhbXBsZS5lZHUvY3JlZGVudGlhbHMvMzczMiIsImlzc yI6Imh0dHBzOi8vZXhhbXBsZS5jb20va2V5cy9mb28uandrIiwibmJmIjoxNTQxNDkzNzI0LCJpYXQiO jE1NDE0OTM3MjQsImV4cCI6MTU3MzAyOTcyMywibm9uY2UiOiI2NjAhNjM0NUZTZXIiLCJ2YyI6eyJAY 29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd 3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZ UNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjd CI6eyJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IjxzcGFuIGxhbmc9J2ZyL UNBJz5CYWNjYWxhdXLDqWF0IGVuIG11c2lxdWVzIG51bcOpcmlxdWVzPC9zcGFuPiJ9fX19.KLJo5GAy BND3LDTn9H7FQokEsUEi8jKwXhGvoN3JtRa51xrNDgXDb0cq1UTYB-rK4Ft9YVmR1NI_ZOF8oGc_7wAp 8PHbF2HaWodQIoOBxxT-4WNqAxft7ET6lkH-4S6Ux3rSGAmczMohEEf8eCeN-jC8WekdPl6zKZQj0YPB 1rx6X0-xlFBs7cl6Wt8rfBP_tZ9YgVWrQmUWypSioc0MUyiphmyEbLZagTyPlUyflGlEdqrZAv6eSe6R txJy6M1-lD7a5HTzanYTWBPAUHDZGyGKXdJw-W_x0IWChBzI8t3kpG253fg6V3tPgHeKXE94fz_QpYfg --7kLsyBAfQGbg

Before switching to "Verifiable Credential" mode the verifier would work directly with the received JWT and follow the steps in RFC7515 Section 5.2 to check that the signature (the bold part) is correct (i.e. it is indeed the signature of the header (the text in italics) concatenated with the payload (the text inside " ")). Once the verifier is happy with the JWS signature, the decoded payload (which in this case will look something like this:)

{
  "sub": "did:example:ebfeb1f712ebc6f1c276e12ec21",
  "jti": "http://example.edu/credentials/3732",
  "iss": "https://example.com/keys/foo.jwk",
  "nbf": 1541493724,
  "iat": 1541493724,
  "exp": 1573029723,
  "nonce": "660!6345FSer",
  "vc": {
    "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
    ],
    "type": [
      "VerifiableCredential",
      "UniversityDegreeCredential"
    ],
    "credentialSubject": {
      "degree": {
        "type": "BachelorDegree",
        "name": "<span lang='fr-CA'>Baccalauréat en musiques numériques</span>"
      }
    }
  }
}

can be transformed into the VC Data model (we intend to ship convenience functions for this):

{
      "@context": [
      "https://www.w3.org/2018/credentials/v1",
      "https://www.w3.org/2018/credentials/examples/v1"
        ],
    "type": [
      "VerifiableCredential",
      "UniversityDegreeCredential"
    ],
    "id": "http://example.edu/credentials/3732",
    "issuer": "https://example.com/keys/foo.jwk",
    "expirationDate": "2019-11-06T08:42:03+00:00",
    "issuanceDate": "2018-11-06T08:42:04+00:00",
    "credentialSubject": {
      "id": did:example:ebfeb1f712ebc6f1c276e12ec21,
      "degree": {
        "type": "BachelorDegree",
        "name": "<span lang='fr-CA'>Baccalauréat en musiques numériques</span>"
      },
    }
    "nonStandardFields" : {
        "nonce": "660!6345FSer",
        "iat": "1541493724",
    }
}

The Verifier may now run futher validations such as checking that the expiration date is not in the past etc.

Note in this example that 1) No proof is attached to the reconstructed JSON-LD document because the JWT has already been verified and 2) the order of the keys in the reconstructed document doesn't matter, again because the received JWT has already been verified.

On the Issuer side the issuer produces a JWT by following RFC7515 Section 5.1. If the crypto IC is capable of signing arbitrary strings/bytes I believe it should be capable of computing the JWS signature (step 5 in the aforementioned section) and then all that is left to do is to assemble the JWT. As we saw in the verification walk through above it doesn't matter how one arrives at the payload (with or without sorting fields in the original JSON-LD document) because it is the resulting JWT that the verifier verifies and validations happen after that.

In light of this we are wondering if the proposed VC-JWT approach would work for you after all, or if perhaps we are missing something? It is a bit hard for us to tell since we don't know exactly which procedures the embedded device does itself vs what can be delegated to more capable devices.

mighty840 commented 1 year ago

Hi @PhilippGackstatter

Thanks for the response. Mostly, VCs will be issued by high level devices like PC Software or PC software interacting with TPMs or HSMs. From that PoV, I think this should not be a problem. I would need to however check this internally and revert back in case only if it poses a big blocker.

For DIDs, before uploading, we need to add proofs (especially for other keys, which we use for key exchange and assertion methods). Will this be also in the same way as for VCs, that we create a JWS/JWT representation?

olivereanderson commented 1 year ago

Hello @mighty840,

For DIDs, before uploading, we need to add proofs (especially for other keys, which we use for key exchange and assertion methods). Will this be also in the same way as for VCs, that we create a JWS/JWT representation?

How one secures DID documents usually depends on the DID method being used. For instance when creating a new DID with our new UTXO method the DID document itself will neither contain a proof field, nor will it be protected by a JWT. Instead its integrity relies on the guarantees provided by the IOTA protocol itself. For this reason the JWT functionality we have in mind is mainly intended to be used in the context of verifiable credentials and verifiable presentations.