---
title: "Assinar um documento XML - PKI Express"
description: "Como assinar documentos XML com o PKI Express: XAdES do documento inteiro em duas etapas com o Web PKI ou com uma chave no servidor, assinatura de um elemento pelo Id (NF-e, COD) e as políticas de assinatura XML."
canonical: "https://docs.lacunasoftware.com/articles/pki-express/xml-signature"
locale: "pt-BR"
product: "PKI Express"
last_updated: "2026-10-13"
---

# Assinar um documento XML - PKI Express

O [PKI Express](https://docs.lacunasoftware.com/articles/pki-express) assina documentos XML no seu servidor: o documento inteiro ou um elemento, em duas etapas, com o certificado do
usuário e o [Web PKI](https://docs.lacunasoftware.com/articles/web-pki), ou em uma etapa, com uma chave que o servidor guarda. 
Os comandos `start-xml`, `complete-sig` e `sign-xml` existem desde o PKI Express 1.0.0. 

O código é Node.js, dos [samples do PKI Suite](https://github.com/LacunaSoftware/PkiSuiteSamples), com o `pki-express` (1.16.2), e PHP,
com o `lacuna/pki-express` (1.17.0), para as assinaturas de elementos. Só as bibliotecas Node.js, Java e PHP assinam XML; as bibliotecas
Python e Ruby não têm classes de XML. 

## Fluxo com o certificado do usuário

O fluxo é o da [assinatura de PDF](https://docs.lacunasoftware.com/articles/pki-express/pades-signature#fluxo-com-o-certificado-do-usuário), com `XmlSignatureStarter`:

1. **Navegador**: o Web PKI lê o certificado do usuário; a página envia o conteúdo.
1. **Servidor**: `XmlSignatureStarter.start()` devolve o hash a assinar, o algoritmo de hash e um arquivo de transferência.
1. **Navegador**: o Web PKI assina o hash com `signHash()`.
1. **Servidor**: `SignatureFinisher.complete()`, com o mesmo XML, grava o XML assinado.

## Assinar o documento inteiro

```js
const signatureStarter = new XmlSignatureStarter();
Util.setPkiDefaults(signatureStarter);
signatureStarter.signaturePolicy = StandardSignaturePolicies.XADES_BES;
signatureStarter.setXmlToSignFromPathSync(StorageMock.getSampleDocPath(SampleDocs.SAMPLE_XML));
signatureStarter.setCertificateFromBase64Sync(certContent);
signatureStarter.start()
	.then((response) => {
		const { toSignHash } = response;
		const { digestAlgorithm } = response;
		const { transferFile } = response;
		// render the page that signs the hash with Web PKI's signHash()
	}).catch((err) => next(err));
```

Depois, conclua como na assinatura de PDF, com o XML como arquivo a assinar e uma saída `.xml`: 

```js
const signatureFinisher = new SignatureFinisher();
Util.setPkiDefaults(signatureFinisher);
signatureFinisher.setFileToSignFromPathSync(StorageMock.getSampleDocPath(SampleDocs.SAMPLE_XML));
signatureFinisher.setTransferFileFromPathSync(transferFile);
signatureFinisher.signature = signature;
const outputFile = `${uuidv4()}.xml`;
signatureFinisher.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
signatureFinisher.complete(true).then((certificate) => { /* signed XML at outputFile */ });
```

## Assinar com uma chave no servidor

O `XmlSigner` assina em uma chamada, sem navegador; o sample usa um arquivo PKCS #12 de teste com a senha `1234`, ou um gerado a partir de
um certificado emitido pelo sample do Amplia. 

```js
const signer = new XmlSigner();
Util.setPkiDefaults(signer);
signer.signaturePolicy = StandardSignaturePolicies.XADES_BES;
await signer.setXmlToSignFromPath(StorageMock.getSampleDocPath(SampleDocs.SAMPLE_XML));
await signer.setPkcs12FromPath(StorageMock.getSamplePkcs12Path());
signer.certPassword = '1234';
const outputFile = `${uuidv4()}.xml`;
signer.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
let signerCert = await signer.sign(true);
```

As outras origens de chave (thumbprint de um certificado, nome de uma chave, certificado em nuvem) são as mesmas dos PDFs: veja
[Assinar com uma chave no servidor](https://docs.lacunasoftware.com/articles/pki-express/pades-signature#assinar-com-uma-chave-no-servidor). 

## Assinar um elemento

Defina `toSignElementId` com o valor do atributo `Id` do elemento a assinar; o PKI Express o recebe como `--element-id`. 

### Nota fiscal eletrônica (NF-e)

O sample de NF-e assina o elemento `infNFe` com a política do padrão nacional da NF-e: 

```php
$signatureStarter = new XmlSignatureStarter();
Util::setPkiDefaults($signatureStarter);
$signatureStarter->signaturePolicy = StandardSignaturePolicies::NFE_PADRAO_NACIONAL;
$signatureStarter->toSignElementId = 'NFe35141214314050000662550010001084271182362300';
$signatureStarter->setXmlToSign(StorageMock::getSampleDocPath(SampleDocs::SAMPLE_NFE));
$signatureStarter->setCertificateBase64($certContent);
$response = $signatureStarter->start();
```

Depois, o `complete()` funciona como acima, com o `SignatureFinisher` e o mesmo XML. 

### Certificado de origem (COD)

O sample de COD faz duas assinaturas de elemento encadeadas em um envelope COD: primeiro o elemento `COD`, depois o `CODEH` no arquivo que a
primeira assinatura gerou, cada uma com a política COD e em duas etapas. 

```php
$signatureStarter->signaturePolicy = StandardSignaturePolicies::COD_WITH_SHA1;
$signatureStarter->toSignElementId = 'COD';    // then 'CODEH' on the signed file
```

### Onde fica a assinatura

O Node.js (`setSignatureElementInsertion`) e o Java (`setSignatureElementInsertion` com `XmlElementInsertion`) escolhem onde o elemento da
assinatura é inserido: `append-child`, `prepend-child`, `append-sibling` ou `prepend-sibling`. Isso exige o PKI Express 1.26.0 ou posterior. 
TODO(docs): onde o PKI Express insere a assinatura por padrão.

## Políticas de assinatura

| Constante (Node.js) | Valor | Observações |
|---|---|---|
| `XADES_BES` | `xades` | |
| `XML_DSIG_BASIC` | `basic` | XMLDSig; o PKI Express 1.32.0 acrescentou uma variante com SHA-1 só para assinaturas legadas |
| `NFE_PADRAO_NACIONAL` | `nfe` | NF-e |
| `PKI_BRAZIL_XML_ADR_BASICA` | `adrb` | ICP-Brasil |
| `PKI_BRAZIL_XML_ADR_TEMPO` | `adrt` | ICP-Brasil; exige uma autoridade de carimbo de tempo |
| `PKI_BRAZIL_XML_ADR_COMPLETA` | `adrc` | ICP-Brasil; exige uma autoridade de carimbo de tempo |
| `PKI_BRAZIL_XML_ADR_ARQUIVAMENTO` | `adra` | ICP-Brasil, PKI Express 1.25.0 ou posterior; exige uma autoridade de carimbo de tempo |
| `COD_WITH_SHA1`, `COD_WITH_SHA256` | `cod-sha1`, `cod-sha256` | COD, PKI Express 1.6 ou posterior |
| `COD_WITH_SHA256_EC14N` | `cod-sha256-ec14n` | COD com a transformação extra `xml-exc-c14n#`, PKI Express 1.36.0 |

* O Java dá às constantes nomes em camel case (`XadesBes`, `NFePadraoNacional`, `CodWithSHA1`) e acrescenta `XadesBrazil` (`xades-brazil`) e
  `PkiBrazilXadesWithCertProtection`. 
* TODO(docs): o que as políticas de geração `xades-brazil` e `pki-brazil-with-cert-protection` produzem.
* TODO(docs): quais bibliotecas cliente definem a opção `classic-enveloped-transform` que o PKI Express 1.27.0 acrescentou; só o Java a tem
  (`setUseClassicEnvelopedTransform`). 

## Em cada linguagem

| Biblioteca | XML (início) | Elemento | Chave no servidor |
|---|---|---|---|
| Node.js | `XmlSignatureStarter.setXmlToSignFromPath` | `toSignElementId` | `XmlSigner` |
| Java | `XmlSignatureStarter.setXmlToSign` | `setToSignElementId` | `XmlSigner` |
| PHP | `XmlSignatureStarter.setXmlToSign` | `toSignElementId` ou `setToSignElementId` | `XmlSigner` |

## Erros

Um comando que falha termina com um código de retorno do PKI Express, como 14 (`ValidationFailed`) ou 32 (`TimestampOptionsRequired`). Veja
[Códigos de retorno](https://docs.lacunasoftware.com/articles/pki-express/return-codes). 

## Veja também

* [Validar assinaturas](https://docs.lacunasoftware.com/articles/pki-express/validate-signatures#assinaturas-xml), para abrir um XML assinado
* [Assinar um PDF (PAdES)](https://docs.lacunasoftware.com/articles/pki-express/pades-signature) e [Assinar com CAdES](https://docs.lacunasoftware.com/articles/pki-express/cades-signature)
* [Serviços de certificado digital em nuvem](https://docs.lacunasoftware.com/articles/pki-express/config/trust-services), para o sample de XML com certificado em nuvem
* [Referência rápida do PKI Express](https://docs.lacunasoftware.com/articles/pki-express/quick-reference)

**Demonstrações e exemplos**

- Assinar um documento XML com o PKI Express: [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/xml-signature-express.js)
- Assinar um documento XML com uma chave do servidor usando o PKI Express: [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/xml-server-key-express.js)
- Assinar uma NF-e com o PKI Express: [Node.js](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/nodejs/expressmvc/routes/xml-nfe-signature-express.js) · [PHP](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/xml-nfe-signature-express/index.php)
- Assinar um XML COD com o PKI Express: [PHP](https://github.com/LacunaSoftware/PkiSuiteSamples/blob/master/php/plain/public/xml-cod-signature-express/index.php)
