# Certificados

Gerenciamento de certificados ICP-Brasil para autenticacao mTLS e assinatura digital XMLDSig com o BACEN.

## Pre-requisitos

- Certificados ICP-Brasil validos emitidos por Autoridade Certificadora credenciada
- OpenSSL 3.x instalado para manipulacao de certificados
- Acesso ao Kubernetes para criar/atualizar Secrets com certificados
- Compreensao basica de PKI (Public Key Infrastructure) e mTLS

## Tipos de Certificados ICP-Brasil

O BACEN exige dois tipos de certificados para operacao no SPI/DICT:

```mermaid
flowchart TB
    subgraph ICP["ICP-Brasil"]
        AC["Autoridade Certificadora"]
    end

    subgraph CPIC["CPIC — Autenticacao"]
        CA["Certificado de Autenticacao"]
        KA["Chave Privada"]
        CA --- KA
    end

    subgraph CPIA["CPIA — Assinatura"]
        CS["Certificado de Assinatura"]
        KS["Chave Privada"]
        CS --- KS
    end

    AC -->|Emite| CPIC
    AC -->|Emite| CPIA

    subgraph Uso["Uso"]
        MTLS["mTLS com BACEN<br/>(conexao HTTPS)"]
        XML["XMLDSig<br/>(assinatura de mensagens)"]
    end

    CPIC --> MTLS
    CPIA --> XML
```

| Tipo | Sigla | Uso | Algoritmo | Validade Tipica |
|------|-------|-----|-----------|----------------|
| Certificado de Autenticacao | CPIC | mTLS com RSFN (conexao HTTPS) | RSA 2048+ | 1-3 anos |
| Certificado de Assinatura | CPIA | XMLDSig (assinatura de mensagens ISO 20022) | RSA 2048+ | 1-3 anos |

### Cadeia de Certificacao

```
ICP-Brasil Raiz v5
  └── AC BACEN (Autoridade Certificadora do BACEN)
       ├── CPIC: Certificado de Autenticacao (mTLS)
       └── CPIA: Certificado de Assinatura (XMLDSig)
```

## Ciclo de Vida dos Certificados

### 1. Solicitacao

```bash
# Gerar CSR para CPIC (autenticacao)
openssl req -new -newkey rsa:2048 -nodes \
  -keyout cpic-key.pem \
  -out cpic.csr \
  -subj "/C=BR/ST=SP/L=Sao Paulo/O=Sua Instituicao/OU=TI/CN=ISPB-12345678"

# Gerar CSR para CPIA (assinatura)
openssl req -new -newkey rsa:2048 -nodes \
  -keyout cpia-key.pem \
  -out cpia.csr \
  -subj "/C=BR/ST=SP/L=Sao Paulo/O=Sua Instituicao/OU=TI/CN=ISPB-12345678-SIGN"
```

Envie os CSRs para a Autoridade Certificadora ICP-Brasil credenciada pelo BACEN.

### 2. Instalacao

Apos receber os certificados assinados:

```bash
# Verificar o certificado CPIC
openssl x509 -in cpic.pem -text -noout

# Verificar a cadeia de confianca
openssl verify -CAfile bacen-ca-chain.pem cpic.pem

# Verificar que a chave privada corresponde ao certificado
openssl x509 -noout -modulus -in cpic.pem | openssl md5
openssl rsa -noout -modulus -in cpic-key.pem | openssl md5
# Os hashes MD5 devem ser identicos
```

### 3. Configuracao no Kubernetes

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: bacen-certificates
  namespace: pix
type: Opaque
data:
  # Certificados (base64)
  bacen-ca.pem: <base64 da cadeia CA do BACEN>
  cpic.pem: <base64 do certificado CPIC>
  cpic-key.pem: <base64 da chave privada CPIC>
  cpia.pem: <base64 do certificado CPIA>
  cpia-key.pem: <base64 da chave privada CPIA>
```

```bash
# Criar Secret a partir de arquivos
kubectl create secret generic bacen-certificates -n pix \
  --from-file=bacen-ca.pem \
  --from-file=cpic.pem \
  --from-file=cpic-key.pem \
  --from-file=cpia.pem \
  --from-file=cpia-key.pem
```

### Variaveis de Ambiente

```yaml
# deploy/backend.yaml (trecho)
env:
  - name: BACEN_CA_CERT_PATH
    value: /certs/bacen-ca.pem
  - name: BACEN_CLIENT_CERT_PATH
    value: /certs/cpic.pem
  - name: BACEN_CLIENT_KEY_PATH
    value: /certs/cpic-key.pem
volumeMounts:
  - name: bacen-certs
    mountPath: /certs
    readOnly: true
volumes:
  - name: bacen-certs
    secret:
      secretName: bacen-certificates
```

### 4. Rotacao (Zero-Downtime)

A rotacao de certificados pode ser feita sem interromper o servico:

```mermaid
sequenceDiagram
    participant OP as Operador
    participant K8s as Kubernetes
    participant CP as CertificatePool
    participant B as BACEN

    OP->>K8s: Atualizar Secret com novo certificado
    K8s->>CP: Volume atualizado (propagacao ~60s)
    Note over CP: CertificatePool recarrega a cada 5 minutos
    CP->>CP: Detectar novo certificado
    CP->>CP: Carregar novo cert + manter antigo
    CP->>B: Proxima requisicao usa novo certificado
    Note over B: BACEN aceita ambos durante periodo de transicao
    OP->>K8s: Remover certificado antigo (apos confirmacao)
```

**Procedimento passo a passo:**

```bash
# 1. Criar novo Secret com o certificado atualizado
kubectl create secret generic bacen-certificates-new -n pix \
  --from-file=bacen-ca.pem \
  --from-file=cpic.pem=cpic-novo.pem \
  --from-file=cpic-key.pem=cpic-key-novo.pem \
  --from-file=cpia.pem=cpia-novo.pem \
  --from-file=cpia-key.pem=cpia-key-novo.pem \
  --dry-run=client -o yaml | kubectl apply -f -

# 2. Aguardar propagacao do volume (~60s) + refresh do CertificatePool (~5min)
sleep 360

# 3. Verificar nos logs que o novo certificado foi carregado
kubectl logs -n pix deployment/pix-backend | grep -i "certificate"

# 4. Testar comunicacao com BACEN
kubectl exec -n pix deployment/pix-backend -- \
  bin/monetarie_pix rpc "Shared.Bacen.Client.health_check()"
```

### 5. Revogacao

Em caso de comprometimento da chave privada:

1. Revogar imediatamente junto a Autoridade Certificadora
2. Notificar o BACEN sobre a revogacao
3. Gerar novo par de chaves + CSR
4. Obter novo certificado e instalar conforme procedimento acima
5. Atualizar o Secret no Kubernetes

## CertificatePool (GenServer)

O `Shared.Crypto.CertificatePool` gerencia os certificados em memoria com refresh periodico:

```mermaid
flowchart TB
    CP["CertificatePool<br/>(GenServer)"] --> LOAD["Carregar certificados<br/>do disco"]
    LOAD --> MEM["Armazenar em memoria"]
    MEM --> TIMER["Timer: 5 minutos"]
    TIMER --> RELOAD["Recarregar do disco"]
    RELOAD --> MEM

    subgraph Consumidores
        BC["Bacen.Client<br/>(mTLS)"]
        XS["Crypto.XmlSigner<br/>(XMLDSig)"]
        XV["Crypto.XmlVerifier<br/>(verificacao)"]
    end

    MEM --> BC & XS & XV
```

| Parametro | Valor | Descricao |
|-----------|-------|-----------|
| Refresh | 5 minutos | Intervalo de recarga dos certificados |
| Fallback | Certificado anterior | Se o novo certificado falhar, mantem o anterior |
| Supervisao | `Shared.Application` | Reiniciado automaticamente pelo supervisor |

## XMLDSig (Assinatura Digital)

### Especificacao

O FluxiQ PIX implementa a assinatura XML conforme especificacao BACEN:

| Aspecto | SPI | DICT |
|---------|-----|------|
| References | 3 (KeyInfo por ID, AppHdr URI vazia, Document sem URI) | 2 (AppHdr + Document) |
| Localizacao da Assinatura | `<Sgntr>` dentro de `<AppHdr>` | `<Sgntr>` dentro de `<AppHdr>` |
| Canonicalizacao | Exclusive XML C14N (`xml-exc-c14n#`) | Exclusive XML C14N (`xml-exc-c14n#`) |
| Algoritmo de Assinatura | RSA-SHA256 (`rsa-sha256`) | RSA-SHA256 (`rsa-sha256`) |
| Algoritmo de Digest | SHA-256 (`sha256`) | SHA-256 (`sha256`) |

### Fluxo de Assinatura

```mermaid
sequenceDiagram
    participant APP as Aplicacao
    participant XS as XmlSigner
    participant CP as CertificatePool
    participant C14N as ExcC14N

    APP->>XS: assinar(xml_document)
    XS->>CP: obter_certificado_cpia()
    CP-->>XS: {cert, private_key}
    XS->>C14N: canonicalizar(references)
    C14N-->>XS: xml_canonicalizado
    XS->>XS: SHA-256 digest de cada Reference
    XS->>XS: Construir SignedInfo
    XS->>C14N: canonicalizar(SignedInfo)
    C14N-->>XS: signed_info_c14n
    XS->>XS: RSA-SHA256 sign(signed_info_c14n, private_key)
    XS->>XS: Inserir <Signature> no <AppHdr>/<Sgntr>
    XS-->>APP: xml_assinado
```

### Modulos de Criptografia

| Modulo | Localizacao | Funcao |
|--------|-------------|--------|
| `Shared.Crypto.XmlSigner` | `apps/shared/lib/shared/crypto/xml_signer.ex` | Assinatura XMLDSig |
| `Shared.Crypto.XmlVerifier` | `apps/shared/lib/shared/crypto/xml_verifier.ex` | Verificacao de assinatura |
| `Shared.Crypto.ExcC14N` | `apps/shared/lib/shared/crypto/exc_c14n.ex` | Canonicalizacao XML exclusiva |
| `Shared.Crypto.CertificateManager` | `apps/shared/lib/shared/crypto/certificate_manager.ex` | Gerenciamento de certificados |
| `Shared.Crypto.CertificatePool` | `apps/shared/lib/shared/crypto/certificate_pool.ex` | Pool com refresh periodico |
| `Shared.Crypto.JwsSigner` | `apps/shared/lib/shared/crypto/jws_signer.ex` | Assinatura JWS para tokens |

## Caminhos de Armazenamento

### Producao (Kubernetes)

| Certificado | Caminho no Container | Secret |
|-------------|---------------------|--------|
| CA BACEN | `/certs/bacen-ca.pem` | `bacen-certificates` |
| CPIC (autenticacao) | `/certs/cpic.pem` | `bacen-certificates` |
| CPIC (chave privada) | `/certs/cpic-key.pem` | `bacen-certificates` |
| CPIA (assinatura) | `/certs/cpia.pem` | `bacen-certificates` |
| CPIA (chave privada) | `/certs/cpia-key.pem` | `bacen-certificates` |

### Desenvolvimento (Local)

```bash
# Estrutura local de certificados
backend/
  priv/
    certs/
      dev-ca.pem          # CA auto-assinada para desenvolvimento
      dev-cpic.pem         # Certificado CPIC de teste
      dev-cpic-key.pem     # Chave privada CPIC de teste
      dev-cpia.pem         # Certificado CPIA de teste
      dev-cpia-key.pem     # Chave privada CPIA de teste
```

## Certificados de Teste (Desenvolvimento/Homologacao)

Para ambientes de desenvolvimento e homologacao, gere certificados auto-assinados:

```bash
# Criar CA de desenvolvimento
openssl req -x509 -new -nodes -newkey rsa:2048 \
  -keyout dev-ca-key.pem -out dev-ca.pem \
  -days 3650 -subj "/CN=FluxiQ Dev CA"

# Criar certificado CPIC de teste
openssl req -new -nodes -newkey rsa:2048 \
  -keyout dev-cpic-key.pem -out dev-cpic.csr \
  -subj "/CN=FluxiQ Dev CPIC/O=FluxiQ/C=BR"

openssl x509 -req -in dev-cpic.csr \
  -CA dev-ca.pem -CAkey dev-ca-key.pem \
  -CAcreateserial -out dev-cpic.pem -days 365

# Criar certificado CPIA de teste
openssl req -new -nodes -newkey rsa:2048 \
  -keyout dev-cpia-key.pem -out dev-cpia.csr \
  -subj "/CN=FluxiQ Dev CPIA/O=FluxiQ/C=BR"

openssl x509 -req -in dev-cpia.csr \
  -CA dev-ca.pem -CAkey dev-ca-key.pem \
  -CAcreateserial -out dev-cpia.pem -days 365

# Limpar CSRs
rm -f *.csr *.srl
```

::: warning APENAS PARA DESENVOLVIMENTO
Certificados auto-assinados **nao** sao aceitos pelo BACEN. Para homologacao e producao, utilize certificados ICP-Brasil emitidos por AC credenciada.
:::

## Verificacao de Certificados

### Verificar Validade

```bash
# Verificar data de expiracao
openssl x509 -in cpic.pem -noout -enddate
# notAfter=Mar 15 23:59:59 2027 GMT

# Verificar informacoes completas
openssl x509 -in cpic.pem -noout -text | head -30

# Verificar cadeia de confianca
openssl verify -CAfile bacen-ca-chain.pem cpic.pem
# cpic.pem: OK
```

### Monitorar Expiracao

```bash
# Script para verificar dias restantes
CERT_PATH="/certs/cpic.pem"
EXPIRY=$(openssl x509 -in $CERT_PATH -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

echo "Certificado expira em $DAYS_LEFT dias"

if [ $DAYS_LEFT -lt 30 ]; then
  echo "ALERTA: Certificado expira em menos de 30 dias!"
fi
```

## Resultado Esperado

Apos a configuracao dos certificados:

- O `CertificatePool` carrega os certificados na inicializacao (log: `"Certificates loaded"`)
- A comunicacao mTLS com BACEN e estabelecida sem erros de handshake SSL
- As mensagens XML sao assinadas com XMLDSig RSA-SHA256 valido
- O refresh automatico detecta novos certificados a cada 5 minutos
- A rotacao de certificados ocorre sem interromper o servico
- `openssl verify` confirma a cadeia de confianca dos certificados instalados
