Files
rustfs/protocol/agent/v1/fixtures/offline-enrollment/error-codes.json
T
2026-09-05 10:23:35 +08:00

118 lines
5.5 KiB
JSON

{
"protocolVersion": "v1",
"fixtureSet": "offline-enrollment",
"fixture": "error-codes",
"description": "Frozen ErrorInfo reasons for offline enrollment. Clients branch on status and reason, never on message.",
"domain": "rustfs.connect",
"detailType": "type.googleapis.com/google.rpc.ErrorInfo",
"disclosureRules": [
"A rejection never reveals whether a presented key or challenge belongs to another tenant.",
"A rejection never contains key material, signature octets, nonces, or document bytes.",
"A rejection never reports which of several failed checks failed first beyond the single frozen reason."
],
"reasons": [
{
"reason": "DOCUMENT_MALFORMED",
"httpStatus": 400,
"status": "INVALID_ARGUMENT",
"meaning": "An enrollment challenge envelope or decoded challenge document cannot provide the padded-base64 JSON structure and pre-verification fields required to locate its trust chain and signing key. No partial challenge is processed."
},
{
"reason": "UNSUPPORTED_PROTOCOL",
"httpStatus": 400,
"status": "INVALID_ARGUMENT",
"meaning": "The protocolVersion is missing, malformed, or names an unsupported major version. Identical to the rule frozen in protocol/agent/v1/authentication.md."
},
{
"reason": "UNSUPPORTED_FORMAT",
"httpStatus": 400,
"status": "INVALID_ARGUMENT",
"meaning": "The formatVersion is not one of the frozen supported format versions."
},
{
"reason": "SIGNATURE_MALFORMED",
"httpStatus": 400,
"status": "INVALID_ARGUMENT",
"meaning": "A top-level challenge or response signature algorithm is not ES256, keyId is malformed, the value is not 64 octets of fixed-width r||s in unpadded base64url, or r or s is out of range. A trust-link signature failure is TRUST_CHAIN_INVALID instead."
},
{
"reason": "SIGNATURE_NOT_CANONICAL",
"httpStatus": 400,
"status": "INVALID_ARGUMENT",
"meaning": "The signature is well formed and verifies, but its s exceeds half the group order. Only the low-S form is accepted."
},
{
"reason": "SIGNATURE_INVALID",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "ECDSA verification over the received octets failed. The document was altered, or it was signed by another key."
},
{
"reason": "ENROLLMENT_ROOT_UNKNOWN",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The first trust link is issued by a key that is not pinned in this build. There is no path from this to acceptance: the root is never learned."
},
{
"reason": "TRUST_CHAIN_INVALID",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The pinned-root chain has the wrong length or role order, or a trust link is structurally invalid, exceeds its role validity limit, fails its signature check, names the wrong issuer, or is outside its validity at the challenge issuedAt."
},
{
"reason": "CONNECT_KEY_UNCHAINED",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The challenge connectKeyId is not the subject of the last trust link, so nothing under the pinned root vouches for the signing key."
},
{
"reason": "CHALLENGE_UNKNOWN",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "Connect has no issued challenge with this challengeId."
},
{
"reason": "CHALLENGE_NOT_YET_VALID",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The evaluation time is more than the skew tolerance before issuedAt."
},
{
"reason": "CHALLENGE_EXPIRED",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The evaluation time is more than the skew tolerance after effectiveExpiresAt, which never exceeds issuedAt plus the frozen maximum challenge lifetime."
},
{
"reason": "CHALLENGE_PROOF_INVALID",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The response nonce or challengeProof is not the one Connect issued for this challenge."
},
{
"reason": "DEVICE_PROOF_INVALID",
"httpStatus": 401,
"status": "UNAUTHENTICATED",
"meaning": "The response signature does not verify under the devicePublicKey it presents, or deviceKeyId is not that key fingerprint. Proof of possession failed."
},
{
"reason": "ENROLLMENT_REPLAYED",
"httpStatus": 409,
"status": "ABORTED",
"meaning": "The challenge was already consumed. A challenge is single use even when the replayed response is byte identical."
},
{
"reason": "ORGANIZATION_MISMATCH",
"httpStatus": 403,
"status": "PERMISSION_DENIED",
"meaning": "The response names a different organization than the challenge it answers."
},
{
"reason": "CLUSTER_MISMATCH",
"httpStatus": 403,
"status": "PERMISSION_DENIED",
"meaning": "The response names a different cluster than the challenge it answers."
}
]
}