docs: update documentation files and project README structure
This commit is contained in:
+174
-108
@@ -1,28 +1,52 @@
|
||||
# CyberCore Signing Protocol (CCSP/1)
|
||||
|
||||
O **CyberCore Signing Protocol (CCSP)** é o protocolo padrão para comunicação local entre aplicações web rodando no navegador e o agente desktop **CyberCore Signer**.
|
||||
> **Especificação Técnica do Protocolo de Comunicação Local e API REST (Versão 1)**
|
||||
|
||||
A versão inicial descrita neste documento é a **CCSP/1**.
|
||||
O **CyberCore Signing Protocol (CCSP)** é o protocolo padrão para comunicação local entre aplicações web rodando no navegador do usuário e o agente desktop **CyberCore Signer**.
|
||||
|
||||
A versão atual especificada neste documento é a **CCSP/1**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Princípios de Segurança
|
||||
## 1. Princípios de Segurança e Isolamento
|
||||
|
||||
1. **Isolamento de Rede:** O servidor local escuta exclusivamente no endereço de loopback `127.0.0.1` (porta padrão `21325`), impedindo qualquer acesso a partir da rede local (LAN) ou externa (WAN).
|
||||
2. **Controle Estrito de Origem (CORS):** O agente valida cabeçalhos `Origin` e responde apenas a pré-voos `OPTIONS` com origens autorizadas.
|
||||
3. **Registro e Autorização de Aplicações:** Nenhuma aplicação desconhecida tem acesso a certificados ou assinaturas. Ao tentar conectar pela primeira vez, uma caixa de diálogo nativa solicita aprovação explícita do usuário.
|
||||
4. **Confirmação Visual da Assinatura:** Toda operação de assinatura exige confirmação manual na interface gráfica, exibindo a aplicação solicitante, o hash do documento e o certificado selecionado.
|
||||
5. **Proteção Contra Ataques de Replay:** Toda requisição deve conter um `nonce` UUID único com validação temporal (`expires_at` ou `timestamp`). Requisições com nonces repetidos são sumariamente rejeitadas (`REPLAY_DETECTED`).
|
||||
6. **Privacidade Criptográfica:** Apenas o **digest (hash)** do documento é enviado ao agente. O documento completo nunca sai da aplicação web e a chave privada nunca sai do dispositivo/computador do usuário.
|
||||
O protocolo CCSP/1 adota o princípio de menor privilégio e segurança em profundidade:
|
||||
|
||||
1. **Loopback Estrito (`127.0.0.1`):** O servidor HTTP local vincula seu socket exclusivamente ao endereço IP `127.0.0.1` na porta padrão `21325`. O agente rejeita escuta em `0.0.0.0`, prevenindo qualquer acesso proveniente da rede local (LAN) ou externa (WAN).
|
||||
2. **Validação de Cabeçalhos e DNS Rebinding:** O agente valida o cabeçalho `Host` para garantir que as requisições se originem estritamente de `127.0.0.1:21325` ou `localhost:21325`.
|
||||
3. **Controle de Origem (CORS):** Todas as respostas incluem cabeçalhos CORS restritivos. Métodos HTTP `OPTIONS` prévios (preflight) são tratados para liberar apenas métodos e headers homologados (`Content-Type`, `Origin`, `X-CyberCore-AppId`).
|
||||
4. **Handshake de Autorização de Aplicações:** Nenhuma página web desconhecida pode listar certificados ou solicitar assinaturas. Uma aplicação deve se identificar (`POST /ccsp/v1/authorize`) e obter aprovação explícita do usuário via diálogo nativo do sistema operacional.
|
||||
5. **Proteção Anti-Replay com Nonce e TTL:** Todas as chamadas de assinatura exigem um identificador pseudoaleatório `nonce` único e um timestamp de expiração (`expires_at`). Requisições com nonces repetidos são sumariamente rejeitadas com erro estruturado `REPLAY_DETECTED`.
|
||||
6. **Privacidade Criptográfica por Digest:** Por padrão, a aplicação web calcula o hash SHA-256 no próprio navegador utilizando a Web Crypto API nativa e envia apenas o digest de 32 bytes (em Base64). O documento confidencial nunca trafega para o agente e a chave privada nunca sai do computador ou do chip criptográfico do usuário.
|
||||
7. **Trava FIFO Serializada (`signLock`):** O processamento de assinaturas físicas em smartcards/tokens USB A3 é serializado em fila FIFO para evitar colisões no hardware mono-thread do middleware do fabricante.
|
||||
|
||||
---
|
||||
|
||||
## 2. Endpoints do Protocolo (CCSP/1)
|
||||
## 2. Visão Geral dos Endpoints (CCSP/1)
|
||||
|
||||
### 2.1 `GET /ccsp/v1/status`
|
||||
Verifica se o agente está instalado, em execução e pronto para operações.
|
||||
| Método | Endpoint | Finalidade | Autenticação Requerida |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/ccsp/v1/status` | Verifica integridade e status de prontidão do agente local | Nenhuma |
|
||||
| `POST` | `/ccsp/v1/authorize` | Handshake de autorização inicial de uma aplicação web | Consentimento visual do usuário |
|
||||
| `GET` | `/ccsp/v1/certificates` | Lista certificados digitais ICP-Brasil válidos e operacionais | Aplicação Autorizada |
|
||||
| `POST` | `/ccsp/v1/sign` | Executa assinatura digital do digest informado | Aplicação Autorizada + Diálogo Nativo |
|
||||
| `POST` | `/ccsp/v1/authenticate` | Realiza login seguro via desafio criptográfico (*Challenge-Response*) | Aplicação Autorizada + Diálogo Nativo |
|
||||
|
||||
#### Resposta de Sucesso (200 OK)
|
||||
---
|
||||
|
||||
## 3. Especificação Detalhada dos Endpoints
|
||||
|
||||
### 3.1 `GET /ccsp/v1/status`
|
||||
Verifica se o agente desktop está instalado, em execução e pronto para operações criptográficas.
|
||||
|
||||
#### Requisição
|
||||
```http
|
||||
GET /ccsp/v1/status HTTP/1.1
|
||||
Host: 127.0.0.1:21325
|
||||
Origin: https://meusistema.empresa.com.br
|
||||
```
|
||||
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
@@ -30,20 +54,58 @@ Verifica se o agente está instalado, em execução e pronto para operações.
|
||||
"agent": "CyberCore Signer",
|
||||
"agent_version": "0.1.0",
|
||||
"os": "Windows 11",
|
||||
"timestamp": "2026-10-08T19:40:00Z"
|
||||
"timestamp": "2026-10-11T20:45:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 `GET /ccsp/v1/certificates`
|
||||
Retorna a lista de certificados digitais atualmente disponíveis e aptos para assinatura.
|
||||
### 3.2 `POST /ccsp/v1/authorize`
|
||||
Inicia o handshake para autorizar uma nova aplicação web. Quando a aplicação ainda não foi homologada pelo usuário, o CyberCore Signer suspende a requisição e exibe um modal nativo na tela do desktop para confirmação.
|
||||
|
||||
#### Headers / Parâmetros
|
||||
- `X-CyberCore-AppId`: UUID da aplicação autorizada (ou query param `?application_id=uuid`).
|
||||
#### Cabeçalhos
|
||||
- `Content-Type: application/json`
|
||||
- `Origin: https://meusistema.empresa.com.br`
|
||||
|
||||
#### Payload da Requisição
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"application_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"name": "Portal Jurídico e Tributário"
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"status": "authorized",
|
||||
"application_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"message": "Aplicação autorizada pelo usuário com sucesso."
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta de Recusa do Usuário (`403 Forbidden`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"status": "error",
|
||||
"error_code": "APPLICATION_NOT_AUTHORIZED",
|
||||
"message": "O usuário recusou a autorização para esta aplicação."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 `GET /ccsp/v1/certificates`
|
||||
Retorna a lista de certificados digitais atualmente disponíveis e aptos para assinatura no sistema (A1 importados e A3 conectados via Windows Store ou PKCS#11).
|
||||
|
||||
#### Cabeçalhos / Parâmetros
|
||||
- `Origin`: Origem web autorizada.
|
||||
- `X-CyberCore-AppId` (Header) ou `?application_id=uuid` (Query Param).
|
||||
|
||||
#### Resposta de Sucesso (200 OK)
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
@@ -51,16 +113,18 @@ Retorna a lista de certificados digitais atualmente disponíveis e aptos para as
|
||||
"certificates": [
|
||||
{
|
||||
"id": "win-4340656a",
|
||||
"alias": "CLAUDIO SILVA:12345678900",
|
||||
"common_name": "CLAUDIO SILVA:12345678900",
|
||||
"subject_dn": "CN=CLAUDIO SILVA:12345678900, OU=Autenticado por AR, O=ICP-Brasil, C=BR",
|
||||
"issuer_dn": "CN=AC SERPRO v5, O=ICP-Brasil, C=BR",
|
||||
"alias": "MARIA DA SILVA:12345678900",
|
||||
"common_name": "MARIA DA SILVA:12345678900",
|
||||
"subject_dn": "CN=MARIA DA SILVA:12345678900, OU=Autenticado por AR, O=ICP-Brasil, C=BR",
|
||||
"issuer_dn": "CN=AC SERPRO v5, OU=Servico Federal de Processamento de Dados, O=ICP-Brasil, C=BR",
|
||||
"type": "A3",
|
||||
"provider_id": "provider-win-store",
|
||||
"device_name": "Token / Smart Card (Windows CAPI/CNG)",
|
||||
"valid_from": "2024-05-10T12:00:00Z",
|
||||
"valid_to": "2027-05-10T12:00:00Z",
|
||||
"device_name": "Token USB / Smart Card (Windows CAPI/CNG)",
|
||||
"valid_from": "2025-01-10T10:00:00Z",
|
||||
"valid_to": "2028-01-10T10:00:00Z",
|
||||
"serial_number": "72910482910482019482",
|
||||
"cpf": "12345678900",
|
||||
"cnpj": null,
|
||||
"can_sign": true,
|
||||
"status": "AVAILABLE"
|
||||
}
|
||||
@@ -70,33 +134,10 @@ Retorna a lista de certificados digitais atualmente disponíveis e aptos para as
|
||||
|
||||
---
|
||||
|
||||
### 2.3 `POST /ccsp/v1/authorize`
|
||||
Handshake inicial de uma nova aplicação web para solicitar autorização ao usuário.
|
||||
### 3.4 `POST /ccsp/v1/sign`
|
||||
Solicita a assinatura digital local do digest informado com o certificado escolhido.
|
||||
|
||||
#### Requisição
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"application_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"name": "Portal Assinaturas Jurídicas"
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta (200 OK)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"status": "authorized",
|
||||
"application_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.4 `POST /ccsp/v1/sign`
|
||||
Executa a assinatura digital do digest informado (PDF, XML, documentos ou arquivos gerais).
|
||||
|
||||
#### Requisição
|
||||
#### Payload da Requisição
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
@@ -106,103 +147,128 @@ Executa a assinatura digital do digest informado (PDF, XML, documentos ou arquiv
|
||||
"algorithm": "SHA256withRSA",
|
||||
"digest": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=",
|
||||
"certificate_hint": "win-4340656a",
|
||||
"document_name": "contrato_locacao.pdf",
|
||||
"document_name": "contrato_prestacao_servicos.pdf",
|
||||
"document_type": "PDF",
|
||||
"nonce": "c4ca4238a0b923820dcc509a6f75849b",
|
||||
"expires_at": "2026-10-08T19:45:00Z"
|
||||
"expires_at": "2026-10-11T20:50:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta de Sucesso (200 OK)
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"request_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
||||
"status": "signed",
|
||||
"signature": "MEUCIQDq...base64...",
|
||||
"certificate": "MIIFazC...base64...",
|
||||
"signature": "MEUCIQDq95kZc...Base64...",
|
||||
"certificate": "MIIFazCCBF...Base64...",
|
||||
"certificate_chain": [
|
||||
"MIIFazC...base64...",
|
||||
"MIIEazC...base64..."
|
||||
"MIIFazCCBF...Base64...",
|
||||
"MIIEazCCA1...Base64..."
|
||||
],
|
||||
"algorithm": "SHA256withRSA",
|
||||
"subject_name": "CLAUDIO SILVA",
|
||||
"subject_name": "MARIA DA SILVA",
|
||||
"subject_cpf_cnpj": "12345678900",
|
||||
"document_name": "contrato_locacao.pdf",
|
||||
"document_name": "contrato_prestacao_servicos.pdf",
|
||||
"document_type": "PDF"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.5 `POST /ccsp/v1/authenticate`
|
||||
Executa o login / autenticação digital segura de um usuário em sistemas web via desafio criptográfico (Challenge-Response ICP-Brasil).
|
||||
### 3.5 `POST /ccsp/v1/authenticate`
|
||||
Executa o login criptográfico de um usuário em sistemas web através do mecanismo de desafio e resposta (*Challenge-Response*).
|
||||
|
||||
#### Requisição
|
||||
#### Payload da Requisição
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"request_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
||||
"request_id": "8f3b201a-8c9d-4e5f-b012-3456789abcde",
|
||||
"application_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"operation": "authenticate",
|
||||
"challenge": "server-session-challenge-nonce-2026",
|
||||
"challenge": "session-nonce-random-server-token-998877",
|
||||
"certificate_hint": "win-4340656a",
|
||||
"purpose": "AUTHENTICATION",
|
||||
"nonce": "c4ca4238a0b923820dcc509a6f75849b",
|
||||
"expires_at": "2026-10-08T19:45:00Z"
|
||||
"nonce": "d3b07384d113edec49eaa6238ad5ff00",
|
||||
"expires_at": "2026-10-11T20:50:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta de Sucesso (200 OK)
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"request_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
||||
"request_id": "8f3b201a-8c9d-4e5f-b012-3456789abcde",
|
||||
"status": "authenticated",
|
||||
"signature": "MEUCIQDq...base64...",
|
||||
"certificate": "MIIFazC...base64...",
|
||||
"signature": "MEQCIF61pP...Base64...",
|
||||
"certificate": "MIIFazCCBF...Base64...",
|
||||
"certificate_chain": [
|
||||
"MIIFazC...base64..."
|
||||
"MIIFazCCBF...Base64...",
|
||||
"MIIEazCCA1...Base64..."
|
||||
],
|
||||
"algorithm": "SHA256withRSA",
|
||||
"subject_name": "CLAUDIO SILVA",
|
||||
"subject_cpf_cnpj": "12345678900",
|
||||
"document_type": "AUTH_CHALLENGE"
|
||||
}
|
||||
```
|
||||
|
||||
#### Resposta de Erro (400/403/404)
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"request_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
||||
"status": "error",
|
||||
"error_code": "USER_CANCELLED",
|
||||
"message": "Operação de assinatura cancelada pelo usuário."
|
||||
"subject_name": "MARIA DA SILVA",
|
||||
"subject_cpf_cnpj": "12345678900"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Tabela de Códigos de Erro Estruturados
|
||||
## 4. Estrutura Padrão de Erro e Códigos HTTP
|
||||
|
||||
| Código | Significado |
|
||||
|---|---|
|
||||
| `CERTIFICATE_NOT_FOUND` | Certificado indicado no hint não foi encontrado. |
|
||||
| `CERTIFICATE_EXPIRED` | O certificado selecionado está fora do período de vigência. |
|
||||
| `CERTIFICATE_INVALID` | O certificado é inválido ou corrompido. |
|
||||
| `PRIVATE_KEY_NOT_AVAILABLE` | Chave privada inacessível ou ausente. |
|
||||
| `TOKEN_NOT_FOUND` | Nenhum dispositivo ou leitor compatível foi localizado. |
|
||||
| `TOKEN_REMOVED` | Dispositivo de hardware foi removido durante a assinatura. |
|
||||
| `PIN_REQUIRED` | PIN obrigatório para liberar chave privada em PKCS#11. |
|
||||
| `PIN_INCORRECT` | PIN digitado está incorreto. |
|
||||
| `PKCS11_ERROR` | Falha no middleware PKCS#11 do fabricante. |
|
||||
| `SIGNATURE_FAILED` | Erro durante a geração da assinatura digital. |
|
||||
| `APPLICATION_NOT_AUTHORIZED` | Aplicação não autorizada ou recusada pelo usuário. |
|
||||
| `REQUEST_EXPIRED` | A data/hora de validade da requisição expirou. |
|
||||
| `REPLAY_DETECTED` | O nonce informado já foi processado anteriormente. |
|
||||
| `INVALID_ORIGIN` | O cabeçalho Origin não corresponde ao cadastro da aplicação. |
|
||||
| `UNSUPPORTED_ALGORITHM` | Algoritmo não suportado (ex: diferente de SHA256withRSA). |
|
||||
| `USER_CANCELLED` | O usuário clicou em Cancelar ou fechou a janela de confirmação. |
|
||||
| `PROVIDER_NOT_AVAILABLE` | O provedor criptográfico necessário está inativo no SO. |
|
||||
| `COMMUNICATION_ERROR` | Erro interno no agente de comunicação local. |
|
||||
Quando qualquer operação falha, o servidor local CCSP/1 responde com um objeto JSON padronizado e o código de status HTTP correspondente:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "1",
|
||||
"request_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
|
||||
"status": "error",
|
||||
"error_code": "PIN_INCORRECT",
|
||||
"message": "O PIN informado para o token A3 é inválido."
|
||||
}
|
||||
```
|
||||
|
||||
### Mapeamento de Status HTTP
|
||||
|
||||
| Código HTTP | Erro Típico | Descrição |
|
||||
|---|---|---|
|
||||
| `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 |
|
||||
|
||||
---
|
||||
|
||||
## 5. Diagrama de Sequência Completo
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User as Usuário
|
||||
participant Browser as Aplicação Web (Browser)
|
||||
participant SDK as @cybercore/signer-sdk
|
||||
participant CCSP as CyberCore CcspServer (127.0.0.1)
|
||||
participant UI as CyberCore Desktop UI
|
||||
participant HW as Hardware Token / Windows MY
|
||||
|
||||
Browser->>SDK: signer.sign({ digest, certId })
|
||||
SDK->>CCSP: POST /ccsp/v1/sign (Headers, AppId, Nonce, Digest)
|
||||
CCSP->>CCSP: Valida Origin, AppId e Nonce (anti-replay)
|
||||
CCSP->>UI: Solicita confirmação visual (requestSignatureConfirmation)
|
||||
UI->>User: Exibe Diálogo Nativo (Aplicação, Documento, Certificado)
|
||||
User->>UI: Clica em "Assinar"
|
||||
opt Certificado A3 exige PIN
|
||||
UI->>User: Solicita PIN do Hardware
|
||||
User->>UI: Digita PIN
|
||||
end
|
||||
UI-->>CCSP: Confirmação concedida
|
||||
CCSP->>HW: signLock.lock() -> JCA/JCE Signature.sign()
|
||||
HW-->>CCSP: Bytes da assinatura + Cadeia X.509
|
||||
CCSP->>CCSP: signLock.unlock()
|
||||
CCSP-->>SDK: 200 OK (signature Base64, cert, subject)
|
||||
SDK-->>Browser: Retorna resultado para a página web
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user