A Estrutura de Assinatura Digital das Convenções de Empacotamento Aberto

 

David Meltzer e Andrey Shur
Microsoft Corporation

Setembro de 2006

Aplica-se a:
   Estrutura de Assinatura Digital OPC
   W3C XML Digital Signature standard
   Microsoft .NET 3.0 Framework

Resumo: discute a Estrutura de Assinatura Digital OPC, fornecendo uma visão geral dos componentes do pacote e dos serviços de suporte, além de exemplos de política de assinatura e sua implementação. (12 páginas impressas)

Sumário

Introdução
Componentes da Estrutura de Assinatura Digital OPC
   O padrão de assinatura digital XML
   Representando assinaturas digitais em pacotes
   Partes e relações de assinatura
Suporte de programação para assinaturas de pacote
   Assinatura de partes e relações do pacote
   Verificando certificados e assinaturas
Política de Assinatura de Aplicativo
   Documentos XPS
   Suporte de programação para assinaturas XPS
Referências

Introdução

O modelo de empacotamento especificado pelo OPC (Open Packaging Conventions) descreve pacotes, partes e relações. Os pacotes contêm partes, que contêm conteúdo e recursos. As relações são definidas para conectar o pacote a partes e para conectar várias partes no pacote.

Este artigo discute a Estrutura de Assinatura Digital OPC, fornecendo uma visão geral dos componentes do pacote e dos serviços de suporte, além de exemplos de política de assinatura e sua implementação.

A Estrutura de Assinatura inclui uma infraestrutura para representar assinaturas digitais e os serviços para criar e validar assinaturas. A Estrutura de Assinatura permite que o padrão de Assinatura Digital XML W3C seja aplicado a partes e relações de pacote.

Usando a Estrutura de Assinatura, os proprietários de formatos baseados em pacote definem e implementam "políticas de assinatura" específicas para seus formatos. As políticas especificam como assinar e validar o conteúdo integral de formatos específicos e incorporar como as assinaturas são usadas para fluxos de trabalho diferentes. Na verdade, para um único formato, pode haver várias políticas definidas para uso em diferentes estágios no ciclo de vida de um documento.

A política de assinatura para um formato baseado em pacote é expressa em termos de assinatura de partes e relações e, possivelmente, outras características do documento (como validação do dispositivo de exibição pretendido, profundidade de cor ou versão do aplicativo). Uma política de assinatura especifica quais componentes de documento assinar e quais deixar sem sinal, se houver. Por exemplo, uma política de assinatura pode ser implementada para permitir que novas partes e relações sejam adicionadas a um pacote ou uma política pode fazer com que uma assinatura seja invalidada se novas partes ou assinaturas forem adicionadas a um pacote.

Este artigo pressupõe familiaridade com a Especificação de Convenções de Empacotamento Aberto e a Sintaxe e Processamento de Assinatura XML de Recomendação W3C.

Componentes da Estrutura de Assinatura Digital OPC

O padrão de assinatura digital XML

A Estrutura de Assinatura para pacotes usa o Padrão de Assinatura Digital XML, conforme definido na Sintaxe e processamento de assinatura XML de recomendação W3C. Esta Recomendação especifica a sintaxe XML e as regras de processamento para produzir e armazenar assinaturas digitais.

O padrão define um tipo de elemento de assinatura XML, esquema e requisitos de conformidade para assinar e validar qualquer tipo de recurso digital. O esquema também define elementos para referenciar recursos e especificar algoritmos relacionados à assinatura.

Recursos de assinaturas digitais

Uma assinatura digital pode ser usada para determinar se o conteúdo assinado foi alterado desde que foi assinado. A assinatura contém um manifesto de conteúdo que é hash de acordo com um algoritmo conhecido e armazenado na assinatura quando criado. Para determinar se o conteúdo foi alterado, um hash do conteúdo assinado é recriado e comparado com o hash armazenado na assinatura.

Uma assinatura digital também pode ser usada para identificar o signatário do conteúdo. A identidade do signatário é representada por um certificado associado à assinatura. O certificado pode ser inserido na assinatura ou estar disponível em outro lugar.

Uma assinatura digital não "bloqueia" um documento nem faz com que ele seja criptografado (embora já possa estar criptografado). O conteúdo do documento permanece inalterado após ser assinado. As assinaturas digitais não impedem que o conteúdo assinado seja exibido por consumidores não intencionais.

Representando assinaturas digitais em pacotes

Os aplicativos incorporam assinaturas digitais em um pacote usando uma configuração especificada de partes e relações.

A Estrutura de Assinatura usa elementos e atributos do namespace de empacotamento, quando permitido pelo padrão de Assinatura Digital XML. Os elementos de assinatura definidos no namespace de empacotamento dão suporte a recursos específicos do pacote que aumentam o padrão sem contradizê-lo. Para obter um resumo das adições, consulte a seção "Modificações na especificação de assinatura digital XML" da Especificação OPC.

As partes do pacote definidas para a Estrutura de Assinatura são a parte Origem, a parte Assinatura XML e a parte Certificado. Cada um tem um tipo de conteúdo bem definido. Tipos de relação bem definidos são usados para conectar partes de assinatura em um pacote, conforme especificado no Apêndice H, "Tipos de Conteúdo e Namespaces Padrão", da Especificação OPC.

Parte de origem da assinatura digital

A parte Origem da Assinatura Digital é o ponto de partida para navegar pelas assinaturas em um pacote. A parte Origem da Assinatura Digital é direcionada da raiz do pacote usando a relação Origem da Assinatura Digital . Várias partes de Assinatura podem ser direcionadas da parte Origem. Se não houver assinaturas no pacote, a parte Origem não estará presente.

Parte da Assinatura XML da Assinatura Digital

As partes de Assinatura XML de Assinatura Digital contêm marcação definida no padrão de Assinatura Digital W3C, bem como no namespace de empacotamento. As partes são direcionadas da parte XML da Origem da Assinatura Digital com a relação assinatura digital .

Parte do certificado de assinatura digital

O certificado X.509 necessário para identificar o signatário, se colocado no pacote, pode ser inserido na parte assinatura XML ou armazenado em uma parte de Certificado separada. A parte opcional do Certificado é direcionada da parte Assinatura XML com a relação Certificado de Assinatura Digital . A parte Certificado pode ser compartilhada entre várias partes de Assinatura.

Partes de assinatura personalizadas

As partes de assinatura personalizadas (específicas do aplicativo) são permitidas, mas não tratadas, pela Estrutura de Assinatura. Uma parte de assinatura que contém uma forma de assinatura diferente de uma assinatura XML deve ser identificada por um tipo de conteúdo personalizado. Além disso, uma relação com um tipo de relação personalizado deve ser usada para direcionar a parte da parte Origem da Assinatura Digital.

Partes e relações de assinatura

O padrão de Assinatura Digital XML permite a assinatura de recursos endereçáveis, que para um pacote são partes. A Estrutura de Assinatura permite a assinatura de partes. As relações em um pacote, armazenadas em uma parte de relações, podem ser assinadas de uma só vez ou um subconjunto de relações pode ser especificado para assinatura.

O tipo de conteúdo de uma parte é assinado, juntamente com o conteúdo da parte, para garantir que uma parte em um pacote assinado seja usada ou renderizada conforme o esperado. Como o tipo de conteúdo não é um recurso endereçável, uma abordagem específica do pacote é usada para assinar o valor do tipo de conteúdo. Quando o pacote é assinado, o tipo de conteúdo de cada parte assinada é armazenado no componente de consulta do URI que se refere à parte assinada. Quando o pacote é consumido, a Estrutura de Assinatura Digital OPC usa o valor do tipo de conteúdo para garantir que o tipo de conteúdo da parte não tenha sido alterado desde que a parte foi assinada.

Quando a parte de relações é assinada como um todo, todas as relações definidas nessa parte são assinadas. Para dar suporte a políticas de assinatura que permitem que alguns conteúdos de um pacote alterem sem invalidar a assinatura, a Estrutura de Assinatura fornece um mecanismo para assinar relações especificadas. Para assinar relações especificadas, a Estrutura de Assinatura usa uma transformação especial, a Transformação relações (consulte Transformar algoritmos).

A Transformação relações cria uma parte de relações que contém apenas o conjunto de relações especificado. A parte de relações obtidas é usada para assinatura e durante a validação de assinatura.

Suporte de programação para assinaturas de pacote

Para assinar e validar assinaturas, os aplicativos podem usar as classes do .NET 3.0 PackageDigitalSignatureManager. As classes específicas do pacote, definidas no namespace System.IO.Packaging , baseiam-se nas classes de assinatura digital do Microsoft .NET 3.0 Framework definidas no namespace System.Security.Cryptography.Xml .

A classe PackageDigitalSignatureManager é usada para criar e validar assinaturas e colocar a infraestrutura de assinatura em um pacote. A assinatura é representada por um objeto baseado na classe PackageDigitalSignature .

Assinatura de partes e relações do pacote

Um aplicativo define uma lista de partes e relações a serem assinadas de acordo com sua política de assinatura. Em seguida, o aplicativo chama o método PackageDigitalSignatureManager.Sign() para criar a assinatura e adicionar a infraestrutura de assinatura ao pacote.

O código de exemplo abaixo demonstra a assinatura de todas as partes no pacote, exceto as partes de relações, a assinatura de todas as relações existentes originadas da raiz do pacote e a inserção do certificado usado para assinar a parte de Assinatura XML. O código de exemplo pressupõe que não existem assinaturas no pacote no início e apenas uma assinatura é aplicada antes da verificação.

Iniciando o processo de assinatura

Para começar a trabalhar com assinaturas no pacote, primeiro crie um PackageDigitalSignatureManager, conforme mostrado abaixo.

    // Open the package.
    Package package = Package.Open(filename);

    // Create the PackageDigitalSignatureManager
      PackageDigitalSignatureManager dsm =
        new PackageDigitalSignatureManager(package);

Opções de inserção de certificado

Um certificado pode ser representado como uma cadeia de caracteres inserida na própria assinatura, como uma parte separada no pacote ou como um recurso fora do pacote. Se o certificado for colocado no pacote, um aplicativo especificará como o certificado será persistido usando as opções de inserção da propriedade PackageDigitalSignature.CertificateOption . Depois de criar a classe PackageDigitalSignatureManager , as opções de inserção para o certificado são definidas, conforme mostrado no código de exemplo abaixo.

    //Specify that the certificate is embedded in the signature held
    //in the XML Signature part.

    //Certificate embedding options include:
    // InSignaturePart – Certificate is embedded in the signature.
    // InCertificatePart – Certificate is embedded in a 
    //                     separate certificate part

    dsm.CertificateOption =
        CertificateEmbeddingOption.InSignaturePart;

Lista de Partes Assinadas

A lista de partes a assinar é especificada usando os URIs que abordam as partes. Neste exemplo, todas as partes do pacote serão assinadas, exceto as partes de relações, que são filtradas usando o método PackUriHelper.IsRelationshipPartUri().

    //Initialize a list to hold the part URIs to sign.

    System.Collections.Generic.List<Uri> partsToSign =
        new System.Collections.Generic.List<Uri>();

    //Add each part to the list, except relationships parts.
    foreach (PackagePart packagePart in package.GetParts())
    {
        if (!PackUriHelper.IsRelationshipPartUri(packagePart.Uri))
      partsToSign.Add(packagePart.Uri);
  }

Lista de Relações Assinadas

As relações individuais são assinadas usando a Transformação relações. Assinar relações dessa forma permite que novas relações sejam adicionadas ao pacote sem invalidar a assinatura.

As relações são selecionadas para assinatura criando uma lista de objetos PackageRelationshipSelector que serão usados no momento da assinatura. Os objetos PackageRelationshipSelector podem ser criados como um tipo de relação de grupo por (conforme definido na seção "Tipos de Conteúdo e Namespaces Padrão" das Convenções de Empacotamento Aberto) ou criados individualmente especificando a ID da relação, como no exemplo abaixo.

     //Create list of selectors for the list of relationships

     List<PackageRelationshipSelector> relationshipSelectors = 
          new List<PackageRelationshipSelector>();

     //Create one selector for each package-level relationship, based on id

  foreach (PackageRelationship relationship in package.GetRelationships())
            {
                relationshipSelectors.Add(new
                    PackageRelationshipSelector(relationship.sourceUri, 
                    PackageRelationshipSelectorType.Id, relationship.Id));
            }

Ao criar um PackageRelationshipSelector com PackageRelationshipSelectorType.Id, a única relação com a ID exclusiva especificada será selecionada para assinatura. Ao criar um seletor com PackageRelationshipSelectorType.Type, todas as relações com o tipo especificado são selecionadas para assinatura. Se as relações do mesmo tipo forem adicionadas posteriormente a um pacote, a assinatura será invalidada.

Criando o objeto Certificate

Antes de assinar, um certificado X.509 válido é obtido criando uma instância de um objeto do tipo System.Security.Cryptography.X509Certificates.X509Certificate2. Esse objeto é passado para o método PackageDigitalSignatureManager.Sign() no momento da assinatura. Para obter mais informações sobre como criar objetos de certificado, consulte o namespace System.Security.Cryptography.X509Certificates .

Aplicando a assinatura

Depois de criar a lista de partes e relações para assinar e obter o objeto de certificado, um aplicativo chama o método PackageDigitalSignatureManager.Sign().

     //Sign package using components created above

     PackageDigitalSignature signature = dsm.Sign(partsToSign, 
          x509Certificate, relationshipSelectors);

     //After signing, close the package.
     //The signature will be persisted in the package.
     package.Close();

Quando o método Sign() é chamado, o hash é gerado e armazenado no manifesto de assinatura e a parte de assinatura é criada. Se a infraestrutura de assinatura já existir no pacote, a nova parte de assinatura será adicionada (se permitido). Se a infraestrutura ainda não existir no pacote, o método Sign() criará a infraestrutura e a colocará no pacote.

Verificando certificados e assinaturas

Os aplicativos podem verificar um certificado ou uma assinatura. Antes de verificar a assinatura, o certificado deve ser verificado. O objeto que representa a assinatura no pacote , PackageDigitalSignature, tem uma propriedade "Signer" que retorna o certificado usado para criar essa assinatura, se ela estiver no pacote. Se o certificado não estiver inserido no pacote, o aplicativo obterá o certificado de um local conhecido pelo aplicativo.

O método PackageDigitalSignatureManager.VerifyCertificate() é usado para validar o certificado obtido, verificando a estrutura do certificado, a data de validade e o status de cadeia. Para obter mais informações sobre status de cadeia, consulte Enumeração X509ChainStatusFlag na Biblioteca de Classes .NET Framework.

Os desenvolvedores de aplicativos podem usar o certificado status para dar suporte às políticas de assinatura. Por exemplo, um aplicativo pode especificar que somente certificados emitidos após determinadas datas são aceitáveis.

O método PackageDigitalSignatureManager.VerifySignatures() é usado para validar todas as assinaturas no pacote. Esse método valida apenas as assinaturas, não os certificados associados às assinaturas.

O código de exemplo abaixo pode ser usado para validar o certificado e a assinatura colocados no pacote nos exemplos de assinatura. O código de exemplo pressupõe que nenhuma assinatura adicional tenha sido adicionada ao pacote.

    // Open the package.

    Package package = Package.Open(filename);

    // Create the PackageDigitalSignatureManager

    PackageDigitalSignatureManager dsm =
        new PackageDigitalSignatureManager(package);

    // Verify the collection of certificates in the package (one, in this case)

        foreach(PackageDigitalSignature signature in pdsm.Signatures)
        {
        if(PackageDigitalSignatureManager.VerifyCertificate(signature.Signer)
            != X509ChainStatusFlags.NoError)
              {
                // Application-specific code for error handling 
                // or certificate validation 
              }
        }
 
   // For this example, if all certificates are valid,
   // verify all signatures in the package.
 
    VerifyResult vResult = dsm.VerifySignatures(false);
    Console.WriteLine("Result " + vResult.ToString());

    // Close the package.

    package.Close();

Política de Assinatura de Aplicativo

Os aplicativos que usam formatos baseados em pacote definem suas próprias políticas como parte da Estrutura de Assinatura. A política é determinada pelos tipos de elemento e pelos requisitos de fluxo de trabalho do formato. Nesta seção, a política de assinatura é descrita para um formato baseado em pacote da Microsoft: o formato documento XPS.

Documentos XPS

O formato do Documento XPS baseia-se nas Convenções de Empacotamento Aberto, conforme especificado na Especificação de Papel XML. A Especificação de Papel XML define a política para assinar documentos XPS. Dentro dessa política, há opções de assinatura disponíveis para dar suporte a recursos de aplicativo ou fluxo de trabalho.

Política de assinatura para pacotes de documentos XPS

A política de assinatura para Documentos XPS descreve o conjunto de partes e relações que devem ser assinadas para que o conteúdo possa ser validado. Como parte dessa política, um aplicativo pode criar uma assinatura que, opcionalmente, inclui uma combinação de partes específicas que são adjuntas ao conteúdo, como a parte CoreProperties. Assinar essas partes impedirá que elas sejam alteradas sem invalidar a assinatura. Além disso, os aplicativos podem, opcionalmente, assinar a parte de relações anexada à parte Origem da Assinatura Digital na assinatura, proibindo que novas assinaturas sejam adicionadas ao documento sem invalidar a assinatura.

Para que uma assinatura seja válida, a política de assinatura do Documento XPS exige que determinadas partes e relações sejam incluídas na assinatura. Nenhuma parte ou relações não reconhecidas pode ser assinada. Ao verificar uma assinatura, um aplicativo deve confirmar se todas as partes e relações necessárias estão assinadas.

Partes do documento XPS para assinar

A tabela a seguir contém a lista de partes que devem ser assinadas em todos os documentos XPS e as partes que são opcionalmente assinadas. Para relações, a política de assinatura XPS especifica que as relações necessárias (relações direcionadas às partes necessárias) são sempre assinadas usando a Transformação de Relações definidas por OPC. Se uma parte for assinada, as relações direcionadas a ela também deverão ser assinadas.

Tipo de Parte Política
Parte FixedDocumentSequence Deve ser assinado
Parte FixedDocument Deve ser assinado
Partes de DocumentStructure Deve ser assinado
Parte SignatureDefinitions Deve ser assinado
Partes de FixedPage Deve ser assinado
Partes de recurso necessárias (como fontes, imagens) Deve ser assinado
Partes de StoryFragments Deve ser assinado
Partes de miniatura Deve ser assinado
Parte CoreProperties Opcionalmente assinado
Parte de Origem da Assinatura Digital Opcionalmente assinado
Parte do Certificado de Assinatura Digital Opcionalmente assinado
Partes printTicket Opcionalmente assinado
Partes de DiscardControl Opcionalmente assinado

Para obter mais informações sobre a política de assinatura XPS, consulte a seção "Recursos do Pacote de Documentos XPS: Assinaturas Digitais: Regras de Assinatura" na Especificação de Papel XML.

Política de Assinatura de Compatibilidade de Marcação

A Especificação de Papel XML descreve um meio para incluir conteúdo alternativo em um documento XPS: compatibilidade de marcação. O conteúdo alternativo é colocado dentro de elementos do namespace De compatibilidade de marcação. Por política, documentos XPS que têm elementos e atributos de compatibilidade de marcação não podem ser assinados com validade, a menos que o aplicativo de assinatura reconheça todas as alternativas de conteúdo como equivalentes. Somente documentos XPS que contêm elementos e atributos reconhecidos podem ser assinados ou validados.

Referendas

Mais de uma assinatura pode ser aplicada ao conteúdo de um documento XPS. Por exemplo, o conteúdo que representa um contrato legal pode exigir que várias pessoas apliquem suas assinaturas, indicando o conteúdo assinado e a identidade do signatário.

Adicionar uma nova assinatura sempre cria uma nova relação dentro da parte relações anexada à parte Origem da Assinatura Digital. Para adicionar novas assinaturas a um Documento XPS sem invalidar assinaturas existentes, essa parte de relações deve permanecer sem sinal (embora um subconjunto de relações possa ser assinado). Se a parte relações estiver incluída em uma assinatura, essa assinatura será invalidada por todas as assinaturas aplicadas posteriormente.

Validando assinaturas XPS

Além de definir a criação de assinatura, a política de assinatura XPS também especifica como verificar uma assinatura como válida. A política define estados de validade para uma assinatura que incluem incompatível, desfeito, questionável e válido, conforme mostrado na tabela a seguir.

Status da Assinatura Todas as partes e relações necessárias estão assinadas? A assinatura inclui apenas conteúdo reconhecido? O hash de conteúdo assinado é verificado? O conteúdo de compatibilidade de marcação assinada é reconhecido? O certificado é válido?
Incompatíveis Não

YES

n/d

Não

n/d

n/d

n/d

n/d

n/d

n/d

Desfeito YES YES Não n/d n/d
Questionável YES

YES

YES

YES

YES

YES

Não

YES

n/d

Não

Válido YES YES YES YES YES

O Visualizador XPS exibe assinaturas XPS questionáveis e quebradas, bem como assinaturas XPS válidas. Assinaturas incompatíveis não são enumeradas.

Suporte de programação para assinaturas XPS

Ao trabalhar com um Documento XPS, os aplicativos podem usar os métodos na classe XpsDigitalSignature . Essa classe é baseada na classe PackageDigitalSignature e inclui métodos que seguem os algoritmos e requisitos especificados na Especificação de Assinatura Digital do XPS. Os métodos de assinatura e validação verificam se todas as partes e relações necessárias de um Documento XPS estão assinadas.

Assinando um documento XPS

O método XpsDocument.SignDigitally() é usado para assinar um documento XPS. Antes de chamar o método , um aplicativo deve ter um certificado X.509, que pode ser obtido usando o objeto System.Security.Cryptography.X509Certificates.X509Certificate2.

     // Open the XPS Document

     XpsDocument document = new XpsDocument(dstContainer,
          FileAccess.ReadWrite);

     // Obtain the certificate object from a file

     X509Certificate certificate =
          509Certificate.CreateFromCertFile(certFilename);

     // Create the signature and add it to the document using
     // the OPC Signing Framework

     document.SignDigitally(certificate, true, 
          XpsDigSigPartAlteringRestrictions.None);

XpsDigSigPartAlteringRestrictions pode ser usado para especificar restrições adicionais para uma assinatura, com base na política de assinatura. Esse parâmetro especifica se as partes CoreMetadata e/ou SignatureOrigin devem ser excluídas da assinatura. As partes excluídas podem ser alteradas posteriormente sem invalidar a assinatura. Por exemplo, excluir a parte CoreMetadata da assinatura permite que um aplicativo altere algumas propriedades do documento sem invalidar a assinatura.

As partes PrintTicket e DiscardControl são excluídas das assinaturas criadas pelo método SignDigitally(), embora essas partes possam ser opcionalmente assinadas de maneira específica do aplicativo.

Verificando uma assinatura de documento XPS

Uma ou muitas assinaturas podem ser armazenadas com um Documento XPS. As assinaturas podem ser obtidas da propriedade XpsDocument.Signatures . Cada assinatura é representada por uma instância do objeto XpsDigitalSignature .

No exemplo abaixo, somente a primeira assinatura na coleção é verificada.

     // Open the XPS Document.

     // Obtain the first enumerated signature.

     foreach (XpsDigitalSignature digitalSignature in
              document.Signatures)
     { 
          // Verify the signature object, if present.

          if (digitalSignature.Verify() ==
     System.IO.Packaging.PackageDigitalSignature.VerifyResult.Success)
          {
         //Signature is valid
          }
     }

Referências