Guias de Desenvolvimento

Signing Sessions

Guias dos SDKs

Certificado Digital A1 (DIGITAL_CERTIFICATE)

Assinatura com certificado digital ICP-Brasil tipo A1. A chave privada nunca sai do lado do cliente — a API fornece o hash a ser assinado, o cliente assina localmente e envia a assinatura de volta.

Etapas geradas: DIGITAL_SIGN_A1


Fluxo Criptográfico

Cliente                                    API SignDocsBrasil
  │                                              │
  │  1. certificateChainPems ──────────────────► │  Valida cadeia
  │                                              │  Prepara PDF
  │  ◄──────────────────── 2. hashToSign         │
  │                                              │
  │  3. Assina hash localmente                   │
  │     (chave privada NUNCA sai do cliente)      │
  │                                              │
  │  4. rawSignatureBase64 ────────────────────► │  Embute no PDF
  │                                              │  Gera CMS/PKCS#7
  │  ◄──────────────────── 5. PDF assinado       │

Passo 1: Criar transação

Use o perfil DIGITAL_CERTIFICATE. Opcionalmente, configure metadados da assinatura digital.

const tx = await client.transactions.create({
  purpose: 'DOCUMENT_SIGNATURE',
  policy: { profile: 'DIGITAL_CERTIFICATE' },
  signer: {
    name: 'João Silva',
    userExternalId: 'user-001',
    cpf: '12345678900',
  },
  document: {
    content: pdfBase64,
    filename: 'contrato.pdf',
  },
  digitalSignature: {
    signatureFieldName: 'Assinatura1',
    signatureReason: 'Aprovação do contrato',
    signatureLocation: 'São Paulo, SP',
  },
});
tx = client.transactions.create(CreateTransactionRequest(
    purpose='DOCUMENT_SIGNATURE',
    policy=Policy(profile='DIGITAL_CERTIFICATE'),
    signer=Signer(name='João Silva', user_external_id='user-001', cpf='12345678900'),
    document=InlineDocument(content=pdf_base64, filename='contrato.pdf'),
    digital_signature=DigitalSignatureMetadata(
        signature_field_name='Assinatura1',
        signature_reason='Aprovação do contrato',
        signature_location='São Paulo, SP',
    ),
))
tx, _ := client.Transactions.Create(ctx, &signdocs.CreateTransactionRequest{
    Purpose: signdocs.TransactionPurposeDocumentSignature,
    Policy:  signdocs.Policy{Profile: signdocs.PolicyProfileDigitalCertificate},
    Signer:  signdocs.Signer{Name: "João Silva", UserExternalID: "user-001", CPF: "12345678900"},
    Document: &signdocs.DocumentInline{Content: pdfBase64, Filename: "contrato.pdf"},
    DigitalSignature: &signdocs.DigitalSignatureMetadata{
        SignatureFieldName: "Assinatura1",
        SignatureReason:    "Aprovação do contrato",
        SignatureLocation:  "São Paulo, SP",
    },
})
CreateTransactionRequest request = new CreateTransactionRequest();
request.purpose = "DOCUMENT_SIGNATURE";
request.policy = new Policy("DIGITAL_CERTIFICATE");
request.signer = new Signer("João Silva", null, "user-001");
request.signer.cpf = "12345678900";
request.document = new CreateTransactionRequest.InlineDocument(pdfBase64, "contrato.pdf");
request.digitalSignature = new CreateTransactionRequest.DigitalSignatureMetadata();
request.digitalSignature.signatureFieldName = "Assinatura1";
request.digitalSignature.signatureReason = "Aprovação do contrato";
request.digitalSignature.signatureLocation = "São Paulo, SP";

Transaction tx = client.transactions().create(request);
$tx = $client->transactions->create(new CreateTransactionRequest(
    purpose: 'DOCUMENT_SIGNATURE',
    policy: new Policy(profile: 'DIGITAL_CERTIFICATE'),
    signer: new Signer(name: 'João Silva', userExternalId: 'user-001', cpf: '12345678900'),
    document: ['content' => $pdfBase64, 'filename' => 'contrato.pdf'],
    digitalSignature: [
        'signatureFieldName' => 'Assinatura1',
        'signatureReason' => 'Aprovação do contrato',
        'signatureLocation' => 'São Paulo, SP',
    ],
));

Passo 2: Preparar assinatura (enviar cadeia de certificados)

Envie a cadeia de certificados PEM (leaf + intermediários). A API valida a cadeia e prepara o hash do documento.

const prep = await client.signing.prepare(tx.transactionId, {
  certificateChainPems: [leafCertPem, intermediateCertPem],
});
console.log(prep.signatureRequestId);  // ID da requisição
console.log(prep.hashToSign);          // Hash a ser assinado (hex)
console.log(prep.hashAlgorithm);       // SHA-256
console.log(prep.signatureAlgorithm);  // RSASSA-PKCS1-v1_5
from signdocs_brasil.models import PrepareSigningRequest

prep = client.signing.prepare(tx.transaction_id, PrepareSigningRequest(
    certificate_chain_pems=[leaf_cert_pem, intermediate_cert_pem],
))
print(prep.signature_request_id)
print(prep.hash_to_sign)
print(prep.hash_algorithm)       # SHA-256
print(prep.signature_algorithm)  # RSASSA-PKCS1-v1_5
prep, _ := client.Signing.Prepare(ctx, tx.TransactionID, &signdocs.PrepareSigningRequest{
    CertificateChainPEMs: []string{leafCertPem, intermediateCertPem},
})
fmt.Println(prep.SignatureRequestID)
fmt.Println(prep.HashToSign)
fmt.Println(prep.HashAlgorithm)      // SHA-256
fmt.Println(prep.SignatureAlgorithm) // RSASSA-PKCS1-v1_5
PrepareSigningResponse prep = client.signing().prepare(tx.transactionId,
    new PrepareSigningRequest(List.of(leafCertPem, intermediateCertPem)));
System.out.println(prep.signatureRequestId);
System.out.println(prep.hashToSign);
System.out.println(prep.hashAlgorithm);      // SHA-256
System.out.println(prep.signatureAlgorithm); // RSASSA-PKCS1-v1_5
$prep = $client->signing->prepare($tx->transactionId, new PrepareSigningRequest(
    certificateChainPems: [$leafCertPem, $intermediateCertPem],
));
echo $prep->signatureRequestId;
echo $prep->hashToSign;
echo $prep->hashAlgorithm;      // SHA-256
echo $prep->signatureAlgorithm; // RSASSA-PKCS1-v1_5

Passo 3: Assinar hash localmente

Assine prep.hashToSign com a chave privada do certificado usando RSASSA-PKCS1-v1_5 com SHA-256. Converta o resultado para base64.

A chave privada NUNCA é enviada para a API. Toda a operação criptográfica ocorre no ambiente do cliente.

import crypto from 'crypto';

const sign = crypto.createSign('SHA256');
sign.update(Buffer.from(prep.hashToSign, 'hex'));
const signatureBase64 = sign.sign(privateKeyPem, 'base64');
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import base64

private_key = serialization.load_pem_private_key(private_key_pem.encode(), password=None)
signature = private_key.sign(
    bytes.fromhex(prep.hash_to_sign),
    padding.PKCS1v15(),
    hashes.SHA256(),
)
signature_base64 = base64.b64encode(signature).decode()
import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "encoding/base64"
    "encoding/hex"
)

hashBytes, _ := hex.DecodeString(prep.HashToSign)
signature, _ := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashBytes)
signatureBase64 := base64.StdEncoding.EncodeToString(signature)
import java.security.Signature;
import java.util.Base64;

byte[] hashBytes = hexToBytes(prep.hashToSign);
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(hashBytes);
byte[] signature = sig.sign();
String signatureBase64 = Base64.getEncoder().encodeToString(signature);
$hashBytes = hex2bin($prep->hashToSign);
openssl_sign($hashBytes, $signature, $privateKey, OPENSSL_ALGO_SHA256);
$signatureBase64 = base64_encode($signature);

Passo 4: Completar assinatura (enviar assinatura raw)

Envie a assinatura base64 de volta para a API. Ela será embutida no PDF junto com a cadeia de certificados.

const result = await client.signing.complete(tx.transactionId, {
  signatureRequestId: prep.signatureRequestId,
  rawSignatureBase64: signatureBase64,
});
console.log(result.status); // COMPLETED
console.log(result.result.digitalSignature.certificateSubject);
console.log(result.result.digitalSignature.signedAt);
from signdocs_brasil.models import CompleteSigningRequest

result = client.signing.complete(tx.transaction_id, CompleteSigningRequest(
    signature_request_id=prep.signature_request_id,
    raw_signature_base64=signature_base64,
))
print(result.status)  # COMPLETED
print(result.result.digital_signature.certificate_subject)
result, _ := client.Signing.Complete(ctx, tx.TransactionID, &signdocs.CompleteSigningRequest{
    SignatureRequestID: prep.SignatureRequestID,
    RawSignatureBase64: signatureBase64,
})
fmt.Println(result.Status)
fmt.Println(result.Result.DigitalSignature.CertificateSubject)
CompleteSigningResponse result = client.signing().complete(tx.transactionId,
    new CompleteSigningRequest(prep.signatureRequestId, signatureBase64));
System.out.println(result.status);
System.out.println(result.result.digitalSignature.certificateSubject);
$result = $client->signing->complete($tx->transactionId, new CompleteSigningRequest(
    signatureRequestId: $prep->signatureRequestId,
    rawSignatureBase64: $signatureBase64,
));
echo $result->status;
echo $result->result['digitalSignature']['certificateSubject'];

Passo 5: Finalizar transação

const finalized = await client.transactions.finalize(tx.transactionId);
const evidence = await client.evidence.get(tx.transactionId);
const download = await client.documents.download(tx.transactionId);
finalized = client.transactions.finalize(tx.transaction_id)
evidence = client.evidence.get(tx.transaction_id)
download = client.documents.download(tx.transaction_id)
client.Transactions.Finalize(ctx, tx.TransactionID)
evidence, _ := client.Evidence.Get(ctx, tx.TransactionID)
download, _ := client.Documents.Download(ctx, tx.TransactionID)
client.transactions().finalize(tx.transactionId);
Evidence evidence = client.evidence().get(tx.transactionId);
DownloadResponse download = client.documents().download(tx.transactionId);
$client->transactions->finalize($tx->transactionId);
$evidence = $client->evidence->get($tx->transactionId);
$download = $client->documents->download($tx->transactionId);

Campos do resultado da assinatura digital

Campo Descrição
certificateSubject DN do certificado (ex: CN=JOAO SILVA, ...)
certificateSerial Número serial do certificado
certificateIssuer DN da autoridade certificadora
algorithm Algoritmo usado (ex: SHA256withRSA)
signedAt Timestamp da assinatura (ISO 8601)
signedPdfHash Hash SHA-256 do PDF assinado
signatureFieldName Nome do campo de assinatura no PDF