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
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 │
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',
],
));
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
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);
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'];
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);
| 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 |