From 275b982507fda128d74d116835051156d874c7ef Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Thu, 9 Feb 2023 14:01:53 +0000 Subject: [PATCH 1/9] proposal for vendor-neutral rest api --- draft-birkholz-scitt-architecture.md | 111 ++++++++++++++++++++------- 1 file changed, 82 insertions(+), 29 deletions(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index 6b5b7ee..79a8e70 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -544,6 +544,29 @@ Editor's Note: This may be moved to appendix. ## Messages +All messages are sent as HTTP GET or POST requests. + +All errors are returned with HTTP 4xx or 5xx status code as JSON objects following the OData JSON (ISO/IEC 20802-2:2016) schema below: + +~~~ +{ + "error": { + "code": "", + "message": "" + } +} +~~~ + +Error codes are machine-readable and defined in this document while error messages are human-readable and implementation-specific. Implementations may return additional error codes not defined in this document. + +All error responses must be sent with the `Content-Type: application/json` header. + +Error responses common to all messages are the following: + +- Status `503` - Service not ready, retry later. + - Error code: implementation-defined + - (Optional) Header: `Retry-Later: ` + ### Register Signed Claims #### Request @@ -552,64 +575,94 @@ Editor's Note: This may be moved to appendix. POST /entries ~~~ +Headers: + +- `Content-Type: application/cose` + Body: SCITT COSE_Sign1 message #### Response One of the following: -- HTTP Status `201` - Registration was tentatively successful pending service consensus. -- HTTP Status `400` - Registration was unsuccessful. - - Error code `AwaitingDIDResolutionTryLater` +- Status `201` - Registration was successful. + - Header `Location: /entries/` + - Header `Content-Type: application/json` + - Body `{ "entryId": "", "status": "registered" }` +- Status `202` - Registration was tentatively successful pending further processing. + - Header `Location: /entries/` + - Header `Content-Type: application/json` + - Body `{ "entryId": "", "status": "pending" }` +- Status `400` - Registration was unsuccessful due to invalid input. - Error code `InvalidInput` -[TODO] Use 5xx for AwaitingDIDResolutionTryLater +A 2xx response must only be returned if all registration policies have passed including signature validation. Clients should retrieve a receipt as proof of registration. -The `201` response contains the `x-ms-ccf-transaction-id` HTTP header which can be used to retrieve the Registration Receipt with the given transaction ID. [TODO] this has to be made generic +A 202 response may be returned if registration policies have passed but further required processing has not finished yet and may still lead to a failure of registration. Clients must check the registration status and may re-submit if registration failed. -[TODO] probably a bad idea to define a new header, or is it ok? can we register a new one? https://www.iana.org/assignments/http-fields/http-fields.xhtml +### Retrieve Registration Entry -The `400` response has a `Content-Type: application/json` header and a body containing details about the error: +#### Request -```json -{ - "error": { - "code": "", - "message": "" - } -} -``` +~~~ +GET /entries/ +~~~ + +#### Response -`AwaitingDIDResolutionTryLater` means the service does not have an up-to-date DID document of the DID referenced in the Signed Claims but is performing or will perform a DID resolution after which the client may retry the request. The response may contain the HTTP header `Retry-After` to inform the client about the expected wait time. +One of the following: -`InvalidInput` means either the Signed Claims message is syntactically malformed, violates the signing profile (e.g. signing algorithm), or has an invalid signature relative to the currently resolved DID document. +- Status `200`. + - Header `Content-Type: application/json` + - Body `{ "entryId": "", "status": "registered|pending|failed" }` +- Status `404` - Entry not found. + - Error code: `NotFound` -### Retrieve Registration Receipt +In eventually consistent systems, implementations must return HTTP status 200 with status code `pending` even if the contacted server is not aware of the newly created entry yet. + +### Retrieve Registered Claim #### Request ~~~ -GET /entries//receipt +GET /entries//claim ~~~ +Query parameters: + +- (Optional) `embedReceipt=true` + +If the query parameter `embedReceipt=true` is provided, then the claim is returned with the corresponding registration receipt embedded in the claim's COSE unprotected header. + #### Response One of the following: -- HTTP Status `200` - Registration was successful and the Receipt is returned. -- HTTP Status `400` - Transaction exists but does not correspond to a Registration Request. - - Error code `TransactionMismatch` -- HTTP Status `404` - Transaction is pending, unknown, or invalid. - - Error code `TransactionPendingOrUnknown` - - Error code `TransactionInvalid` +- Status `200`. + - Header: `Content-Type: application/cose` + - Body: COSE_Sign1 claim +- Status `404` - Invalid Entry ID or registration pending or failed. + - Error `NotFound` -The `200` response contains the SCITT_Receipt in the body. +### Retrieve Registration Receipt -The `400` and `404` responses return the error details as described earlier. +#### Request -The retrieved Receipt may be embedded in the corresponding COSE_Sign1 document in the unprotected header, see TBD. +~~~ +GET /entries//receipt +~~~ + +#### Response + +One of the following: -[TODO] There's also the `GET /entries/` endpoint which returns the submitted COSE_Sign1 with the Receipt already embedded. Is this useful? +- Status `200`. + - Header: `Content-Type: application/cbor` + - Body: SCITT_Receipt +- Status `404` - Invalid Entry ID or registration pending or failed. + - Error `NotFound` + +The retrieved Receipt may be embedded in the corresponding COSE_Sign1 document in the unprotected header, see TBD. # Privacy Considerations From 0b6f24f18d81ce3b5c162160c5993f0bd553df96 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Mon, 13 Feb 2023 10:35:12 +0000 Subject: [PATCH 2/9] operations --- draft-birkholz-scitt-architecture.md | 75 ++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index 79a8e70..b70fa9b 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -559,11 +559,11 @@ All errors are returned with HTTP 4xx or 5xx status code as JSON objects followi Error codes are machine-readable and defined in this document while error messages are human-readable and implementation-specific. Implementations may return additional error codes not defined in this document. -All error responses must be sent with the `Content-Type: application/json` header. +All error responses must be sent with the `Content-Type: application/json` HTTP header. Error responses common to all messages are the following: -- Status `503` - Service not ready, retry later. +- Status 503 - Service not ready, retry later. - Error code: implementation-defined - (Optional) Header: `Retry-Later: ` @@ -585,20 +585,52 @@ Body: SCITT COSE_Sign1 message One of the following: -- Status `201` - Registration was successful. - - Header `Location: /entries/` +- Status 202 - Registration is successful. + - Header `Location: /operations/` - Header `Content-Type: application/json` - - Body `{ "entryId": "", "status": "registered" }` -- Status `202` - Registration was tentatively successful pending further processing. - - Header `Location: /entries/` + - Body `{ "operationId": "", "status": "registered", "entryId": " }` + +- Status 202 - Registration is pending. + - Header `Location: /operations/` - Header `Content-Type: application/json` - - Body `{ "entryId": "", "status": "pending" }` -- Status `400` - Registration was unsuccessful due to invalid input. + - Body `{ "operationId": "", "status": "pending" }` + +- Status 400 - Registration was unsuccessful due to invalid input. - Error code `InvalidInput` -A 2xx response must only be returned if all registration policies have passed including signature validation. Clients should retrieve a receipt as proof of registration. +If 202 is returned with status `pending`, then clients should wait until registration succeeded or failed by polling the registration status using the Operation ID returned in the response. Clients should always obtain a receipt as a proof that registration has succeeded. + +### Retrieve Operation Status + +#### Request + +~~~ +GET /operations/ +~~~ + +#### Response + +One of the following: + +- Status 200 - Registration is pending + - Header: `Content-Type: application/json` + - Body: `{ "operationId": "", "status": "pending" }` + +- Status 200 - Registration was successful + - Header: `Location: /entries/` + - Header: `Content-Type: application/json` + - Body: `{ "operationId": "", "status": "registered", "entryId": "" }` + +- Status 200 - Registration failed + - Header `Content-Type: application/json` + - Body: `{ "operationId": "", "status": "failed", "error": { "code": "", "message": "" } }` + - Error code: `InvalidInput` + +- Status 404 - Unknown Operation ID + - Error code: `NotFound` + - This can happen if the operation ID has expired and been deleted. -A 202 response may be returned if registration policies have passed but further required processing has not finished yet and may still lead to a failure of registration. Clients must check the registration status and may re-submit if registration failed. +If an operation ID is invalid (i.e., it does not correspond to any submit operation), a service may return either a 404 or a `pending` status. This is because differentiating between the two may not be possible in an eventually consistent system. ### Retrieve Registration Entry @@ -612,14 +644,12 @@ GET /entries/ One of the following: -- Status `200`. +- Status 200. - Header `Content-Type: application/json` - - Body `{ "entryId": "", "status": "registered|pending|failed" }` -- Status `404` - Entry not found. + - Body `{ "entryId": "", "status": "registered" }` +- Status 404 - Entry not found. - Error code: `NotFound` -In eventually consistent systems, implementations must return HTTP status 200 with status code `pending` even if the contacted server is not aware of the newly created entry yet. - ### Retrieve Registered Claim #### Request @@ -638,11 +668,12 @@ If the query parameter `embedReceipt=true` is provided, then the claim is return One of the following: -- Status `200`. +- Status 200. - Header: `Content-Type: application/cose` - Body: COSE_Sign1 claim -- Status `404` - Invalid Entry ID or registration pending or failed. - - Error `NotFound` + +- Status 404 - Entry not found. + - Error code: `NotFound` ### Retrieve Registration Receipt @@ -656,11 +687,11 @@ GET /entries//receipt One of the following: -- Status `200`. +- Status 200. - Header: `Content-Type: application/cbor` - Body: SCITT_Receipt -- Status `404` - Invalid Entry ID or registration pending or failed. - - Error `NotFound` +- Status 404 - Entry not found. + - Error code: `NotFound` The retrieved Receipt may be embedded in the corresponding COSE_Sign1 document in the unprotected header, see TBD. From fc3e6962a8e0768cb67e4a0e7533a97ad4efebf7 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Mon, 13 Feb 2023 10:50:58 +0000 Subject: [PATCH 3/9] fix --- draft-birkholz-scitt-architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index b70fa9b..cfb97df 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -662,7 +662,7 @@ Query parameters: - (Optional) `embedReceipt=true` -If the query parameter `embedReceipt=true` is provided, then the claim is returned with the corresponding registration receipt embedded in the claim's COSE unprotected header. +If the query parameter `embedReceipt=true` is provided, then the claim is returned with the corresponding registration receipt embedded in the claim's COSE unprotected header. #### Response From 0a4fcf29967865db9af5bb86862ba261b6baee27 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Tue, 14 Feb 2023 13:24:51 +0000 Subject: [PATCH 4/9] headers --- draft-birkholz-scitt-architecture.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index cfb97df..b9f234c 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -565,7 +565,7 @@ Error responses common to all messages are the following: - Status 503 - Service not ready, retry later. - Error code: implementation-defined - - (Optional) Header: `Retry-Later: ` + - (Optional) Header: `Retry-After: ` ### Register Signed Claims @@ -614,6 +614,7 @@ One of the following: - Status 200 - Registration is pending - Header: `Content-Type: application/json` + - (Optional) Header: `Retry-After: ` - Body: `{ "operationId": "", "status": "pending" }` - Status 200 - Registration was successful From 62b4b9bfe7a03351d9bb62f46f5594a6bdd1a3d6 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Wed, 15 Feb 2023 10:56:50 +0000 Subject: [PATCH 5/9] rename "registered" operation status to "succeeded" & remove status from entry resource --- draft-birkholz-scitt-architecture.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index b9f234c..d933ffe 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -588,7 +588,7 @@ One of the following: - Status 202 - Registration is successful. - Header `Location: /operations/` - Header `Content-Type: application/json` - - Body `{ "operationId": "", "status": "registered", "entryId": " }` + - Body `{ "operationId": "", "status": "succeeded", "entryId": " }` - Status 202 - Registration is pending. - Header `Location: /operations/` @@ -620,7 +620,7 @@ One of the following: - Status 200 - Registration was successful - Header: `Location: /entries/` - Header: `Content-Type: application/json` - - Body: `{ "operationId": "", "status": "registered", "entryId": "" }` + - Body: `{ "operationId": "", "status": "succeeded", "entryId": "" }` - Status 200 - Registration failed - Header `Content-Type: application/json` @@ -647,7 +647,7 @@ One of the following: - Status 200. - Header `Content-Type: application/json` - - Body `{ "entryId": "", "status": "registered" }` + - Body `{ "entryId": "" }` - Status 404 - Entry not found. - Error code: `NotFound` From 0359dc439cf495c759e41d2ecb1596b0fb667be1 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Wed, 15 Feb 2023 12:03:09 +0000 Subject: [PATCH 6/9] use Problem JSON for errors text mostly from RFC9162 --- draft-birkholz-scitt-architecture.md | 46 ++++++++++++++++------------ 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index d933ffe..caff249 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -53,6 +53,8 @@ normative: # RFC9054: COSE-HASH RFC9162: CT RFC6838: + RFC7807: + RFC7231: IANA.cose: DID-CORE: target: https://www.w3.org/TR/did-core/ @@ -546,26 +548,28 @@ Editor's Note: This may be moved to appendix. All messages are sent as HTTP GET or POST requests. -All errors are returned with HTTP 4xx or 5xx status code as JSON objects following the OData JSON (ISO/IEC 20802-2:2016) schema below: +If the transparency service cannot process a client's request, it MUST return an HTTP 4xx or 5xx status code, and the body SHOULD be a JSON problem details object ({{RFC6838}}) containing: + +- type: A URI reference identifying the problem. To facilitate automated response to errors, this document defines a set of standard tokens for use in the type field within the URN namespace of: "urn:ietf:params:scitt:error:". + +- detail: A human-readable string describing the error that prevented the transparency service from processing the request, ideally with sufficient detail to enable the error to be rectified. + +Error responses SHOULD be sent with the `Content-Type: application/problem+json` HTTP header. + +As an example, submitting a claim with an unsupported signature algorithm would return a `400 Bad Request` status code and the following body: ~~~ { - "error": { - "code": "", - "message": "" - } + "type": "urn:ietf:params:scitt:error:badSignatureAlgorithm" + "detail": "The claim was signed with an algorithm the server does not support" } ~~~ -Error codes are machine-readable and defined in this document while error messages are human-readable and implementation-specific. Implementations may return additional error codes not defined in this document. - -All error responses must be sent with the `Content-Type: application/json` HTTP header. +Most error types are specific to the type of request and are defined in the respective subsections below. The one exception is the "malformed" error type, which indicates that the transparency service could not parse the client's request because it did not comply with this document: -Error responses common to all messages are the following: +- Error code: `malformed` (The request could not be parsed). -- Status 503 - Service not ready, retry later. - - Error code: implementation-defined - - (Optional) Header: `Retry-After: ` +Clients SHOULD treat 500 and 503 HTTP status code responses as transient failures and MAY retry the same request without modification at a later date. Note that in the case of a 503 response, the transparency service MAY include a `Retry-After` header field per {{RFC7231}} in order to request a minimum time for the client to wait before retrying the request. In the absence of this header field, this document does not specify a minimum. ### Register Signed Claims @@ -596,7 +600,8 @@ One of the following: - Body `{ "operationId": "", "status": "pending" }` - Status 400 - Registration was unsuccessful due to invalid input. - - Error code `InvalidInput` + - Error code `badSignatureAlgorithm` + - Error code `TBD` If 202 is returned with status `pending`, then clients should wait until registration succeeded or failed by polling the registration status using the Operation ID returned in the response. Clients should always obtain a receipt as a proof that registration has succeeded. @@ -624,13 +629,16 @@ One of the following: - Status 200 - Registration failed - Header `Content-Type: application/json` - - Body: `{ "operationId": "", "status": "failed", "error": { "code": "", "message": "" } }` - - Error code: `InvalidInput` + - Body: `{ "operationId": "", "status": "failed", "error": { "type": "", "detail": "" } }` + - Error code: `badSignatureAlgorithm` + - Error code: `TBD` - Status 404 - Unknown Operation ID - - Error code: `NotFound` + - Error code: `operationNotFound` - This can happen if the operation ID has expired and been deleted. +If an operation failed, then error details are embedded as a JSON problem details object in the `"error"` field. + If an operation ID is invalid (i.e., it does not correspond to any submit operation), a service may return either a 404 or a `pending` status. This is because differentiating between the two may not be possible in an eventually consistent system. ### Retrieve Registration Entry @@ -649,7 +657,7 @@ One of the following: - Header `Content-Type: application/json` - Body `{ "entryId": "" }` - Status 404 - Entry not found. - - Error code: `NotFound` + - Error code: `entryNotFound` ### Retrieve Registered Claim @@ -674,7 +682,7 @@ One of the following: - Body: COSE_Sign1 claim - Status 404 - Entry not found. - - Error code: `NotFound` + - Error code: `entryNotFound` ### Retrieve Registration Receipt @@ -692,7 +700,7 @@ One of the following: - Header: `Content-Type: application/cbor` - Body: SCITT_Receipt - Status 404 - Entry not found. - - Error code: `NotFound` + - Error code: `entryNotFound` The retrieved Receipt may be embedded in the corresponding COSE_Sign1 document in the unprotected header, see TBD. From 52d186941839d12bd064f37eda1fb484d4b7f0b3 Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Wed, 15 Feb 2023 14:45:50 +0000 Subject: [PATCH 7/9] Update draft-birkholz-scitt-architecture.md Co-authored-by: Thomas Fossati --- draft-birkholz-scitt-architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index caff249..a39c287 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -560,7 +560,7 @@ As an example, submitting a claim with an unsupported signature algorithm would ~~~ { - "type": "urn:ietf:params:scitt:error:badSignatureAlgorithm" + "type": "urn:ietf:params:scitt:error:badSignatureAlgorithm", "detail": "The claim was signed with an algorithm the server does not support" } ~~~ From 92f81ef43dcba7318d82d2c425fcdc0505cb84af Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Wed, 15 Feb 2023 14:47:52 +0000 Subject: [PATCH 8/9] json tagging --- draft-birkholz-scitt-architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index a39c287..514d734 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -558,7 +558,7 @@ Error responses SHOULD be sent with the `Content-Type: application/problem+json` As an example, submitting a claim with an unsupported signature algorithm would return a `400 Bad Request` status code and the following body: -~~~ +~~~json { "type": "urn:ietf:params:scitt:error:badSignatureAlgorithm", "detail": "The claim was signed with an algorithm the server does not support" From 61829ca36273030c32cf7e19885d57f2b9f7534b Mon Sep 17 00:00:00 2001 From: Maik Riechert Date: Thu, 16 Feb 2023 11:21:41 +0000 Subject: [PATCH 9/9] separate 201/202 responses on submit --- draft-birkholz-scitt-architecture.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/draft-birkholz-scitt-architecture.md b/draft-birkholz-scitt-architecture.md index 514d734..7a8e9ef 100644 --- a/draft-birkholz-scitt-architecture.md +++ b/draft-birkholz-scitt-architecture.md @@ -589,21 +589,22 @@ Body: SCITT COSE_Sign1 message One of the following: -- Status 202 - Registration is successful. - - Header `Location: /operations/` +- Status 201 - Registration is successful. + - Header `Location: /entries/` - Header `Content-Type: application/json` - - Body `{ "operationId": "", "status": "succeeded", "entryId": " }` + - Body `{ "entryId": " }` - Status 202 - Registration is pending. - Header `Location: /operations/` - Header `Content-Type: application/json` + - (Optional) Header: `Retry-After: ` - Body `{ "operationId": "", "status": "pending" }` - Status 400 - Registration was unsuccessful due to invalid input. - Error code `badSignatureAlgorithm` - Error code `TBD` -If 202 is returned with status `pending`, then clients should wait until registration succeeded or failed by polling the registration status using the Operation ID returned in the response. Clients should always obtain a receipt as a proof that registration has succeeded. +If 202 is returned, then clients should wait until registration succeeded or failed by polling the registration status using the Operation ID returned in the response. Clients should always obtain a receipt as a proof that registration has succeeded. ### Retrieve Operation Status @@ -637,7 +638,7 @@ One of the following: - Error code: `operationNotFound` - This can happen if the operation ID has expired and been deleted. -If an operation failed, then error details are embedded as a JSON problem details object in the `"error"` field. +If an operation failed, then error details SHOULD be embedded as a JSON problem details object in the `"error"` field. If an operation ID is invalid (i.e., it does not correspond to any submit operation), a service may return either a 404 or a `pending` status. This is because differentiating between the two may not be possible in an eventually consistent system.