Change:
on server side. Also, error is unprotected (as all other OSCORE errors) see
RFC7252 specifies that 5.03 uses Max-Age. Now when we use 4.01, I think Max-Age should (need to) be removed.
NAME This was an oversight on my part. One question though: what was the reason to say: Why do we specify for Observe responses? A server MAY set an outer Max-Age=0 with all responses (as an indication to the proxy not to cache), also for error responses (not protected with Object-Security) to an OSCORE request.
The reason why we talked about Max-Age is to avoid caching by a OSCORE unanaware proxy. This was not needed for 2.04. if we change to only 2.04 we should remove this completely.
Ok, because 2.04 is non cacheable. but error responses are cacheable, so following the same logic we should say that the server MAY set max-age = 0 for error responses, no?
Yes, that makes sense.
(This issue takes some context from issue ). The current draft states that replay protection violation triggers a 5.03 with Max-Age 0 (Section 6.4). While this is a practical solution to issue (which is not mitigated by encrypting the code because FETCH is still safe), it could still be caught by a proxy that'd try to be smart about it (and would, AFAICT, be within its rights). I suggest that the response code be 4.01 Unauthorized with Max-Age=0. The semantics of Unauthorized are "SHOULD NOT repeat the request without first improving its authentication status to the server", and while it's a bit of a stretch to say that increasing the sequence number is sufficient to improve the authentication status, the Max-Age gives a good hint ("Come on, try again right away, don't look for other keys"), and clients can use the presence of the Max-Age option as a discriminator to tell "Sorry, no such context" apart from "Retry with a new seqno".
We also just identified this response code as not appropriate. The proposal is good, unless it results in overloading the semantics of Max-Age=0. There is already at least one requirement when Max-Age has to be zero: RFC7252, Section 5.6.1: "If an origin server wishes to prevent caching, it MUST explicitly include a Max-Age Option with a value of zero seconds." Is there a setting where the the server would not want the response 4.01 to be cached even though it is not a replay? (Obviously we have to differentiate between Inner and Outer 4.01, but is that enough?)
I don't know. I briefly thought about using an Echo here, but an HTTP proxy would react to that as a CoAP proxy would to 5.03,Max-Age=0. (See comments 2ff). I did give that some thought, and considering the Echo option thought about whether the server should just reply with an encrypted ,Max-Age=0 (or Echo=short). I decided against suggesting that because responding to a possibly fraudulent message with an owned partial IV means that any adversary that has one valid-but-used message can thus drive any server into partial-IV exhaustion.
By the way, just FYI, that Max-Age=0 with 5.03 means "service unavailable, retry in 0 seconds", which is wrong (and not what we want). (see: URL)
The current text where there MAY be a Max-Age of 0 both on "4.01, Security context not found" and on "4.01, Security context not found" means that a client can not know any more which is the case (and it should not look into the message). I see the reason for the MAY set Max-Age for most error cases in , but a client needs to keep those apart (otherwise it'd need to so something like try 3 times with a new PIV, and if the server still responds the same, assume that it doesn't know the KID). I suggest that for those two responses, the Max-Age values are enforced as "MUST NOT set a Max-Age option" and "MUST set the Max-Age option to 0", or find any other discriminator, but an implementation should be able to tell them apart.
Granted, with the current setup of POST and FETCH there are much fewer cases where replay protection errors can happen (they'd only legally happen under particular package loss situations when starting an observation via a proxy that does not support observation but does do optimizations for safe requests), but I still think that there'd be more clarity if there were a discriminant between the two error cases.

Discussion:
in inner-options. The Outer Max-Age option is used to avoid unnecessary caching of <del> OSCORE responses at OSCORE unaware intermediary nodes.  A server MAY set a Class U Max-Age option with value zero to Observe responses (see Section 5.6.1 of RFC7252) which is then processed according to outer-options.  The Outer Max-Age option value SHALL be discarded by the OSCORE client. </del> <ins> OSCORE error responses at OSCORE unaware intermediary nodes.  A server MAY set a Class U Max-Age option with value zero to OSCORE error responses described in replay-protection, ver-req and ver-res, which is then processed according to outer-options. </ins> <del> Non-Observe OSCORE responses do not need to include a Max-Age option </del> <ins> Non-error OSCORE responses do not need to include a Max-Age option </ins> since the responses are non-cacheable by construction (see coap- header).

In order to protect from replay of requests, the server's Recipient Context includes a Replay Window.  A server SHALL verify that a Partial IV received in the COSE object has not been received before. <del> If this verification fails and the message received is a CON message, the server SHALL respond with a 5.03 Service Unavailable error message with the inner Max-Age option set to 0.  The diagnostic payload MAY contain the "Replay protection failed" string.  The size and type of the Replay Window depends on the use case and lower protocol layers.  In case of reliable and ordered transport from endpoint to endpoint, the server MAY just store the last received Partial IV and require that newly received Partial IVs equals the last received Partial IV + 1. </del> <ins> If this verification fails the server SHALL stop processing the message and, in case of CON respond with a 4.01 Unauthorized error message.  The server MAY set an Outer Max-Age option with value zero. The diagnostic payload MAY contain the "Replay protection failed" string.  The size and type of the Replay Window depends on the use case and lower protocol layers.  In case of reliable and ordered transport from endpoint to endpoint, the server MAY just store the last received Partial IV and require that newly received Partial IVs equals the last received Partial IV + 1. </ins> Responses to non-Observe requests are protected against replay as they are cryptographically bound to the request.

either the decompression or the COSE message fails to decode, the server SHALL respond with a 4.02 Bad Option error message. <ins> The server MAY set an Outer Max-Age option with value zero. </ins> The diagnostic payload SHOULD contain the string "Failed to decode COSE". the server fails to retrieve a Recipient Context with Recipient ID corresponding to the 'kid' parameter received, the server SHALL respond with a 4.01 Unauthorized error message.  The <ins> server MAY set an Outer Max-Age option with value zero.  The </ins> diagnostic payload MAY contain the string "Security context not found".

If decryption fails, the server MUST stop processing the request and, if the request is a CON message, the server MUST <del> respond with a 4.00 Bad Request error message.  The diagnostic </del> <ins> respond with a 4.00 Bad Request error message.  The server MAY set an Outer Max-Age option with value zero.  The diagnostic </ins> payload MAY contain the "Decryption failed" string. If decryption succeeds, update the Replay Window, as described