From e9f90b42cb3d0917c4e5438ca27d2d9e81f0f602 Mon Sep 17 00:00:00 2001 From: Claudecio Martins Date: Tue, 20 Oct 2026 16:28:33 -0300 Subject: [PATCH] docs(ccsp): formalize ccsp v1 json schema error catalog and versioning policy --- docs/CCSP.md | 52 ++++-- docs/ccsp-v1.schema.json | 356 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 397 insertions(+), 11 deletions(-) create mode 100644 docs/ccsp-v1.schema.json diff --git a/docs/CCSP.md b/docs/CCSP.md index 44f393b..8e56971 100644 --- a/docs/CCSP.md +++ b/docs/CCSP.md @@ -357,22 +357,52 @@ Quando qualquer operação falha, o servidor local CCSP/1 responde com um objeto } ``` -### Mapeamento de Status HTTP +### Lista Completa de Códigos de Erro Estruturados -| Código HTTP | Erro Típico | Descrição | +Todos os códigos de erro são estáveis, estruturados e interoperáveis entre o backend Java e o SDK JavaScript: + +| Código de Erro (`error_code`) | Descrição e Causa Raiz | Mapeamento no SDK | |---|---|---| -| `400 Bad Request` | `USER_CANCELLED`, `PIN_INCORRECT`, `SIGNATURE_FAILED` | Requisição malformada, cancelamento pelo usuário ou falha de PIN | -| `401 Unauthorized` | `APPLICATION_NOT_AUTHORIZED` | Aplicação não autorizada ou sem cabeçalho `X-CyberCore-AppId` | -| `403 Forbidden` | `INVALID_ORIGIN` | Cabeçalho `Origin` não confere com o domínio cadastrado | -| `404 Not Found` | `CERTIFICATE_NOT_FOUND`, `TOKEN_NOT_FOUND` | Certificado ou dispositivo físico ausente | -| `409 Conflict` | `REPLAY_DETECTED` | Nonce já utilizado anteriormente na janela de validação | -| `422 Unprocessable`| `REQUEST_EXPIRED`, `CERTIFICATE_EXPIRED` | Parâmetros sintaticamente válidos mas expirados temporalmente | -| `500 Server Error` | `PKCS11_ERROR`, `PROVIDER_NOT_AVAILABLE` | Falha interna no middleware do fabricante ou driver criptográfico | -| `503 Service Unavail`| `TOKEN_REMOVED`, `COMMUNICATION_ERROR` | Hardware desconectado ou serviço em recuperação | +| `CERTIFICATE_NOT_FOUND` | Certificado não encontrado pelo ID ou hint especificado | `CertificateNotFoundError` | +| `CERTIFICATE_EXPIRED` | Certificado ultrapassou a data limite de validade (`notAfter`) | `CertificateExpiredError` | +| `CERTIFICATE_INVALID` | Certificado corrompido, revogado ou com estrutura X.509 inválida | `CertificateInvalidError` | +| `PRIVATE_KEY_NOT_AVAILABLE` | Chave privada inacessível, protegida por hardware desconectado ou ausente | `PrivateKeyNotAvailableError` | +| `TOKEN_NOT_FOUND` | Nenhum token USB, smart card ou leitora física detectada | `TokenNotFoundError` | +| `TOKEN_REMOVED` | O dispositivo físico foi desconectado durante a operação | `TokenNotFoundError` | +| `PIN_REQUIRED` | O hardware criptográfico A3 exige digitação de PIN para desbloqueio | `PinRequiredError` | +| `PIN_INCORRECT` | O PIN digitado pelo usuário foi rejeitado pelo token (risco de bloqueio de PUK) | `PinIncorrectError` | +| `PKCS11_ERROR` | Falha interna no driver, middleware PKCS#11 ou DLL do fabricante | `CyberCoreError` | +| `SIGNATURE_FAILED` | Erro matemático na cifra assimétrica ou payload malformado | `SignatureFailedError` | +| `APPLICATION_NOT_AUTHORIZED` | A aplicação web solicitante não possui autorização concedida pelo usuário | `ApplicationNotAuthorizedError` | +| `REQUEST_EXPIRED` | O timestamp `expires_at` da requisição foi ultrapassado (timeout) | `RequestExpiredError` | +| `REPLAY_DETECTED` | O identificador `nonce` já foi processado anteriormente (ataque de replay) | `ReplayDetectedError` | +| `INVALID_ORIGIN` | O cabeçalho `Origin` não confere com os domínios homologados para o AppId | `InvalidOriginError` | +| `INVALID_HOST` | O cabeçalho `Host` foi adulterado (tentativa de DNS Rebinding) | `CyberCoreError` | +| `UNSUPPORTED_ALGORITHM` | Algoritmo criptográfico solicitado não é suportado pelo provider | `UnsupportedAlgorithmError` | +| `USER_CANCELLED` | O usuário clicou explicitamente em 'Cancelar' no diálogo nativo do sistema | `UserCancelledError` | +| `PROVIDER_NOT_AVAILABLE` | Provedor criptográfico nativo indisponível na plataforma atual | `ProviderNotAvailableError` | +| `COMMUNICATION_ERROR` | Falha na camada de transporte HTTP local do loopback | `CyberCoreError` | +| `AGENT_NOT_RUNNING` | O agente desktop não está rodando em 127.0.0.1:21325 (lado SDK) | `AgentNotRunningError` | --- -## 5. Diagrama de Sequência Completo +## 5. Especificação JSON Schema e Versionamento + +O contrato canônico e exaustivo de todos os endpoints e payloads do protocolo CCSP/1 está formalizado no arquivo: +- [docs/ccsp-v1.schema.json](file:///var/www/cybercore/cybercore-signer/docs/ccsp-v1.schema.json) + +### Política de Versionamento e Retrocompatibilidade + +1. **Identificador de Versão Maior (`version: "1"`):** + - O campo `version` em todos os requests e responses identifica a versão maior do protocolo. O agente desktop garante compatibilidade retroativa com todas as revisões do CCSP/1. +2. **Evolução Aditiva (Não Quebrante):** + - Novos campos opcionais de requisição e novos metadados informativos de resposta podem ser adicionados dentro da versão CCSP/1 sem quebrar clientes existentes. Clientes e servidores devem ignorar propriedades adicionais desconhecidas (`additionalProperties` tolerantes). +3. **Mudança Quebrante (Nova Versão Maior):** + - Qualquer alteração na semântica de autenticação, remoção de campos obrigatórios ou mudança estrutural de URLs exigirá a introdução de uma nova versão de protocolo (ex: CCSP/2 com prefixo `/ccsp/v2/`). O agente manterá os endpoints `/ccsp/v1/` operacionais em paralelo para garantir transição suave. + +--- + +## 6. Diagrama de Sequência Completo ```mermaid sequenceDiagram diff --git a/docs/ccsp-v1.schema.json b/docs/ccsp-v1.schema.json new file mode 100644 index 0000000..29b09d3 --- /dev/null +++ b/docs/ccsp-v1.schema.json @@ -0,0 +1,356 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://cybercore.com.br/schemas/ccsp-v1.json", + "title": "CyberCore Signing Protocol v1 (CCSP/1) Specification", + "description": "Especificação formal do protocolo JSON para comunicação local entre aplicações web e o agente desktop CyberCore Signer.", + "type": "object", + "properties": { + "version": { + "type": "string", + "enum": ["1"], + "description": "Versão do protocolo CCSP (sempre '1' para CCSP/1)." + } + }, + "definitions": { + "ErrorCode": { + "type": "string", + "enum": [ + "CERTIFICATE_NOT_FOUND", + "CERTIFICATE_EXPIRED", + "CERTIFICATE_INVALID", + "PRIVATE_KEY_NOT_AVAILABLE", + "TOKEN_NOT_FOUND", + "TOKEN_REMOVED", + "PIN_REQUIRED", + "PIN_INCORRECT", + "PKCS11_ERROR", + "SIGNATURE_FAILED", + "APPLICATION_NOT_AUTHORIZED", + "REQUEST_EXPIRED", + "REPLAY_DETECTED", + "INVALID_ORIGIN", + "INVALID_HOST", + "UNSUPPORTED_ALGORITHM", + "USER_CANCELLED", + "PROVIDER_NOT_AVAILABLE", + "COMMUNICATION_ERROR", + "BAD_REQUEST", + "METHOD_NOT_ALLOWED" + ], + "description": "Códigos formais de erro estruturados do protocolo CCSP/1." + }, + + "ErrorResponse": { + "type": "object", + "required": ["version", "status", "error_code", "message"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "status": { "type": "string", "enum": ["error"] }, + "error_code": { "$ref": "#/definitions/ErrorCode" }, + "message": { "type": "string" }, + "request_id": { "type": ["string", "null"] } + }, + "additionalProperties": true + }, + + "StatusResponse": { + "type": "object", + "required": ["version", "status", "agent", "agent_version", "os", "timestamp"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "status": { "type": "string", "enum": ["ready", "busy", "error"] }, + "agent": { "type": "string" }, + "agent_version": { "type": "string" }, + "os": { "type": "string" }, + "timestamp": { "type": "string" } + }, + "additionalProperties": true + }, + + "AuthorizeRequest": { + "type": "object", + "required": ["version", "application_id"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "application_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{36}$" }, + "name": { "type": "string" } + }, + "additionalProperties": true + }, + + "AuthorizeResponse": { + "type": "object", + "required": ["version", "status", "application_id"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "status": { "type": "string", "enum": ["authorized"] }, + "application_id": { "type": "string" }, + "message": { "type": "string" } + }, + "additionalProperties": true + }, + + "CertificateItem": { + "type": "object", + "required": ["id", "alias", "type", "can_sign", "status"], + "properties": { + "id": { "type": "string" }, + "alias": { "type": "string" }, + "common_name": { "type": ["string", "null"] }, + "subject_dn": { "type": ["string", "null"] }, + "issuer_dn": { "type": ["string", "null"] }, + "type": { "type": "string", "enum": ["A1", "A3"] }, + "provider_id": { "type": ["string", "null"] }, + "device_name": { "type": ["string", "null"] }, + "valid_from": { "type": ["string", "null"] }, + "valid_to": { "type": ["string", "null"] }, + "serial_number": { "type": ["string", "null"] }, + "cpf": { "type": ["string", "null"] }, + "cnpj": { "type": ["string", "null"] }, + "can_sign": { "type": "boolean" }, + "status": { "type": "string" } + }, + "additionalProperties": true + }, + + "CertificatesResponse": { + "type": "object", + "required": ["version", "status", "certificates"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "status": { "type": "string", "enum": ["success"] }, + "certificates": { + "type": "array", + "items": { "$ref": "#/definitions/CertificateItem" } + } + }, + "additionalProperties": true + }, + + "SealThemeItem": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "description": { "type": ["string", "null"] }, + "width": { "type": "number" }, + "height": { "type": "number" }, + "primary_color": { "type": ["string", "null"] }, + "secondary_color": { "type": ["string", "null"] }, + "background_color": { "type": ["string", "null"] }, + "border_color": { "type": ["string", "null"] }, + "text_color": { "type": ["string", "null"] }, + "icon_style": { "type": ["string", "null"] }, + "custom": { "type": "boolean" } + }, + "additionalProperties": true + }, + + "SealsResponse": { + "type": "object", + "required": ["version", "status", "themes"], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "status": { "type": "string", "enum": ["success"] }, + "default_seal_id": { "type": ["string", "null"] }, + "themes": { + "type": "array", + "items": { "$ref": "#/definitions/SealThemeItem" } + } + }, + "additionalProperties": true + }, + + "SignRequest": { + "type": "object", + "required": [ + "version", + "request_id", + "application_id", + "operation", + "algorithm", + "digest", + "nonce", + "expires_at" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "application_id": { "type": "string" }, + "operation": { "type": "string", "enum": ["sign", "authenticate"] }, + "algorithm": { "type": "string" }, + "digest": { "type": "string", "description": "Digest SHA-256 em Base64" }, + "certificate_hint": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] }, + "document_type": { "type": ["string", "null"] }, + "purpose": { "type": ["string", "null"] }, + "challenge": { "type": ["string", "null"] }, + "nonce": { "type": "string" }, + "expires_at": { "type": "string" } + }, + "additionalProperties": true + }, + + "SignResponse": { + "type": "object", + "required": [ + "version", + "request_id", + "status", + "signature", + "certificate", + "algorithm" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "status": { "type": "string", "enum": ["signed", "authenticated"] }, + "signature": { "type": "string", "description": "Assinatura digital em Base64" }, + "certificate": { "type": "string", "description": "Certificado X.509 do signatário em Base64" }, + "certificate_chain": { + "type": "array", + "items": { "type": "string" } + }, + "algorithm": { "type": "string" }, + "sha256": { "type": ["string", "null"] }, + "subject_name": { "type": ["string", "null"] }, + "subject_cpf_cnpj": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] }, + "document_type": { "type": ["string", "null"] }, + "challenge": { "type": ["string", "null"] } + }, + "additionalProperties": true + }, + + "SignPdfRequest": { + "type": "object", + "required": [ + "version", + "request_id", + "application_id", + "operation", + "pdf", + "nonce", + "expires_at" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "application_id": { "type": "string" }, + "operation": { "type": "string", "enum": ["sign_pdf"] }, + "pdf": { "type": "string", "description": "Documento PDF completo codificado em Base64" }, + "certificate_hint": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] }, + "page": { "type": ["integer", "null"] }, + "page_choice": { "type": ["string", "null"] }, + "position": { "type": ["string", "null"] }, + "x": { "type": ["number", "null"] }, + "y": { "type": ["number", "null"] }, + "scale": { "type": ["number", "null"] }, + "visible_seal": { "type": ["boolean", "null"] }, + "seal_theme_id": { "type": ["string", "null"] }, + "seal_custom": { "type": ["object", "null"] }, + "reason": { "type": ["string", "null"] }, + "location": { "type": ["string", "null"] }, + "cpf_display_mode": { "type": ["string", "null"] }, + "include_date_time": { "type": ["boolean", "null"] }, + "custom_extra_info": { "type": ["string", "null"] }, + "nonce": { "type": "string" }, + "expires_at": { "type": "string" } + }, + "additionalProperties": true + }, + + "SignPdfResponse": { + "type": "object", + "required": [ + "version", + "request_id", + "status", + "signed_pdf", + "signature", + "certificate", + "algorithm" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "status": { "type": "string", "enum": ["signed"] }, + "signed_pdf": { "type": "string", "description": "PDF assinado completo com envelope PAdES em Base64" }, + "sha256": { "type": ["string", "null"] }, + "signature": { "type": "string" }, + "certificate": { "type": "string" }, + "certificate_chain": { + "type": "array", + "items": { "type": "string" } + }, + "algorithm": { "type": "string" }, + "subject_name": { "type": ["string", "null"] }, + "subject_cpf_cnpj": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] } + }, + "additionalProperties": true + }, + + "SignXmlRequest": { + "type": "object", + "required": [ + "version", + "request_id", + "application_id", + "operation", + "nonce", + "expires_at" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "application_id": { "type": "string" }, + "operation": { "type": "string", "enum": ["sign_xml"] }, + "xml": { "type": ["string", "null"], "description": "XML em texto puro UTF-8" }, + "xml_base64": { "type": ["string", "null"], "description": "XML codificado em Base64" }, + "certificate_hint": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] }, + "profile": { "type": ["string", "null"], "enum": ["XADES_BES", "XMLDSIG", null] }, + "target_element_tag": { "type": ["string", "null"] }, + "target_element_id": { "type": ["string", "null"] }, + "algorithm": { "type": ["string", "null"] }, + "nonce": { "type": "string" }, + "expires_at": { "type": "string" } + }, + "additionalProperties": true + }, + + "SignXmlResponse": { + "type": "object", + "required": [ + "version", + "request_id", + "status", + "signed_xml", + "signature", + "certificate", + "algorithm" + ], + "properties": { + "version": { "type": "string", "enum": ["1"] }, + "request_id": { "type": "string" }, + "status": { "type": "string", "enum": ["signed"] }, + "signed_xml": { "type": "string", "description": "Documento XML assinado completo com assinatura enveloped" }, + "sha256": { "type": ["string", "null"] }, + "signature": { "type": "string" }, + "certificate": { "type": "string" }, + "certificate_chain": { + "type": "array", + "items": { "type": "string" } + }, + "algorithm": { "type": "string" }, + "subject_name": { "type": ["string", "null"] }, + "subject_cpf_cnpj": { "type": ["string", "null"] }, + "document_name": { "type": ["string", "null"] } + }, + "additionalProperties": true + } + } +}