PKCS #7
El estándar pkcs #7 es un conjunto de normas para firmar y encriptar
documentos, normalmente usado en el mail para la autenticidad y privacidad
de los datos contenidos en ellos.
De objetos PKCS #7 podemos encontrar varios tipos:
-
data: Sólo datos, usado para enviar datos sin encriptar.
-
signed sata: datos firmados, usado para autentificación del remitente
-
enveloped data: datos juntos - o enfundados - que pueden ser datos o datos
firmados o datos encriptados o varios de ellos a la vez,utilizados para
confidencialidad.
-
signed-and-enveloped data: datos firmados y enfundados. Para autenticidad
y confidencialidad.
-
digested data: datos resumidos, para comprobar la integridad del mensaje.
-
encrypted data: datos encriptados, utilizados para confidencialidad.
Para comprender mejor estos tipos de datos, debemos de adentrarnos más
en el conocimiento de este estándar.
Tipo de contenido "data":
El tipo data es solo la información en una cadena de octetos, sin
ningún tipo de manipulación criptográfica.
Tipo de contenido "signed data":
Es cualquier tipo de datos que estén firmados por uno o varios firmantes
mediante un resumen de los datos y su posterior encriptación utilizando
la clave privada de cada firmante sobre el resumen de los dato, a esta
encriptación del resumen es a lo que se llama firma electrónica.
Para crear un tipo signed data se siguen los siguientes pasos:
-
Para cada firmante, se calcula un resumen con el algoritmo que use el firmante
- si dos firmantes utilizan el mismo algoritmo, el resumen sólo
se calcula para uno de ellos, el otro utiliza el del otro firmante - Si
uno de los firman quiere autentificar cualquier otro tipo de información
que quiera incluir de más, se le calculará el resumen del
mensaje original junto con la información de más que ese
firmante haya querido poner.
-
Para cada firmante, el resumen y la información asociada a éste
se encripta utilizando la clave privada del firmante.
-
Para cada firmante, el resumen del mensaje encriptado y otra información
específica del remitente se agrupan en un campo del objeto llamdo
SignerInfo,
otros datos como una lista de certificados revocados de cada firmante y
sus certificados se agrupan en este paso.
-
Los algoritmos que se han utilizado para resumir el mensaje - de todos
los firmantes - y el campo SignerInfo se agrupan en otro campo
llamado SignedData junto con el mensaje original.
Los pasos que debe realizar el destinatario son más simples:
-
Verificar las firmas desenciptando cada resumen para cada firmante con
la clave pública del mismo - las claves públicas de los firmantes
están dentro del mismo objeto con el formato de certificados.
-
Comparar los resumenes utilizando el mismo algoritmo que utilizó
el firmante al crearlo y compararlo con el extraido del paso anterior.
Tipo de datos en ASN.1 SignedData:
SignedData::= SEQUENCE {
version Version;
digestAlgorithms DigestAlgorithmsIdentifiers,
contentInfo ContentInfo,
certificates
[0] IMPLICIT ExtendedCertificatesAndCertificates
OPTIONAL,
crls
[1] IMPLICIT CertificateRevocationLists
OPTIONAL,
signerInfos SignerInfos
}
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo
Donde:
version es la versión del estándar que se está
utilizando
digestAlgorithms son un conjunto de identificadores de algoritmos
para resúmenes - inclusive ninguno -. Cada elemento identifica el
algoritmo utilizado para resumir el contenido y los parámetros que
se han utilizado.
contentInfo es el objeto que queremos firmar.
certificates es un conjunto de certificados extendidos tipo PKCS#6
y certificados X.509. Se intenta que el conjunto sea suficiente para contenet
certificados hasta una CA raiz reconocida para todos los firmantes que
están en el campo SignersInfo. Pueden haber también
certificados suficientes para que la CA raiz no sea única, en el
caso de que fuera única, los certificados podrán ser verificados
por otros medios.
crls es un conjunto de listas de certificados revocados.
signersInfo es un conjunto de información sobre los firmantes,
pueden haber cualquier número de de elementos, incluido ninguno.
Tipo de datos en ASN.1 SignerInfo:
SignerInfo ::= SEQUENCE {
version Version,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier,
authenticatedAttributes
[0] IMPLICIT Attributes
OPTIONAL,
digestEncryptionAlgorithm
DigestEncryptionAlgorithmIdentifier,
encryptedDigest EncryptedDigest,
unautenticatedAttributes
[1] IMPLICIT Attributes
OPTIONAL
}
EncryptedDigest ::= OCTET STRING
Donde:
version es la version de la sintaxis que se está
utilizando
issuerAndSerialNumber precisa el certificado del firmante - por
supuesto el nombre del mismo y su clave pública - mediante el nombre
de la CA y el número de serie del certificado.
digestAlgorithm identifica el algoritmo utilizado para resumir
el contenido del mensaje y los atributos que se han querido autenticar
con los parametros que se han utilizado al resumir.
authenticatedAttributes son un conjunto de atributos que han sido
firmados. Este campo es opcional, pero debe estar presente si el tipo de
contenido del campo contentInfo no es data. Si el campo está,
entonces debe tener como mínimo dos atributos:
-
un objeto del tipo PKCS#9 atributo del tipo contenido, el cual nos dice
el tipo de contenido que lleva el mensaje.
-
otro objeto tipo PKCS#9 atributo del tipo resumen del mensaje, que nos
dice el resumen del mensaje.
digestEncryptionAlgorithm identifica el algoritmo utilizado para
encriptar el mensaje y la información suplementaria con la clave
privada del firmante.
encryptedDigest es el resumen y la información adicional
encriptados.
unautenticatedAttributes es un conjunto de atributos que no han
sido firmados - este campo no se suele utilizar -.
Nota: los atributos están definidos en el estándar del
PKCS#9.
Ejemplo de objeto PKCS #7 tipo firma
Proceso de resumen de mensajes:
Este proceso calcula un resumen del mensaje que va a ser firmado o el mensaje
y los atributos que van a ser firmados. En cada caso, la entrada serán
los objetos a firmar o, especificamente, los bytes contenidos en el subcampo
ContentInfo
del campo content codificado en DER (base64) que se quiere firmar
- sólo los bytes de datos se resumirán, no los identificadores
de los bytes o los bytes de longitud-.
El resultado del resumen depende de que el campo authenticatedAttributes
esté presente, si no está, el resumen se hará solo
del contenido y si está, el resultado será el resumen de
la codificación en DER del valor Atributtes contenida en
el campo authenticatedAttributes, entonces en el campo Attributes
debe estar también el tipo de contenido y el resumen de ese tipo
como atributo.
Cuando el contenido a firmar es de tipo data y el campo authenticatedAttributes
no está, el resumen se hará solo del valor de data.
Esto tiene la ventaja de que la longitud del contenido a firmar no debe
ser conocida a prioori en el proceso de encriptación.
Aunque los bytes identificadores y la longitud no estén resumidos,
están protegidos por otros medios; los bytes de longitud están
protegido por la naturaleza de los algoritmos de resumen, ya que es computacionalmente
imposible encontrar dos mensajes distintos que tengan el mismo resumen,
además, asumiendo que el tipo de contenido unicamente determine
los bytes identificadores, éstos están protegidos implícitamente
por una de estas dos vías: por la inclusión del tipo de contenido
en los atributos autenticados o por el uso de la compatibilidad con el
PEM, que implica que el tipo de contenido es data.
Proceso de cifrado de mensajes:
Las entradas a este proceso son el resumen en sí del mensaje y el
identificador del algoritmo que se ha utilizado y la salida es el cifrado
con la clave privada del firmante de la codificación en BER del
valor de tipo DigestInfo:
DigestInfo ::= SEQUENCE {
digestAlgorithm DigestAlgorithmIdentifier,
digest Digest
}
Digest ::= OCTET STRING
Donde
digestAlgorithm es el algoritmo que se ha utilizado para resumir
el mensaje y los identificadores autenticados, lógicamente debe
ser el mismo que el presente en el campo digestAlgorithm de la
estructura SignerInfo.
digest es el resumen en sí.
Tipo de contenido "enveloped-data":
Este tipo de contenido consiste en un contenido cifrado de cualquier tipo
junto con la llave de sesión cifrada con la/s clave/s pública/s
de el/los destinatario/s. Ésta combinación es lo que se conoce
como un sobre digital. para cada destinatario. Cualquier tipo de dato se
puede meter en un sobre y enviarlo a cualquier número de destinatarios.
Normalmente, el uso que se dará a este tipo será el
envío a varios destinatarios de contenido cifrado del tipo data,
digested-data
o signed-data.
Para crear un "sobre" necesitamos hacer los siguientes pasos:
Se genera de forma aleatoria una clave de sesión para un algoritmo
de encriptación en particular.
Para cada destinatario, la clave de sesión se cifra con la clave
pública del destinatario
Para cada destinatario, la clave de sesión y alguna otra información
propia del destinatario se agrupa en un valor del tipo RecipientInfo.
El contenido se cifra con la llave de sesión
Los valores del tipo RecipientInfo - uno por cada destinatario - se juntan
con el contenido cifrado del mensaje original, creándose así
el "sobre"
El proceso a seguir por el destinatario es el sigueinte:
El destinatario abre el "sobre" descifrando la única parte que puede
descifrar - la que hace referencia a él ya que esá cifrada
con su clave pública - y descifra la clave de sesión.
Se descifra el contenido utilizando esta clave de sesión que se
ha descifrado antes.
La llave privada del destinatario está referenciada mediante
el nombre de la CA - issuer- y el número de serie del certificado,
entonces únicamente distingue como válido ese certificado
al que referencia.
Tipo de datos en ASN.1 EnvelopedData:
La estructura de datos del tipo EnvelopedData en ASN.1 es la siguiente:
EnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
encryptedContentInfo EncriptedContentInfo
}
RecipientInfos ::= SET OF RecipientInfo
EncryptedContentInfo ::= SEQUENCE {
contentType ContentType,
contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
encryptedContent
[0] IMPLICIT EncryptedContent
OPTIONAL
}
EncryptedContent ::= OCTET STRING
Donde:
version es la versión de la sintaxis con la que se ha hecho
el objeto.
recipientInfos es el conjunto de información sobre los
destinatarios - debe haber al menos uno - .
encryptedContentInfo es el contenido del mensaje cifrado e información
sobre el cifrado del mismo. Dentro de esta estructura encontramos:
-
contentType que es el tipo de contenido del mensaje
-
contentEncryptionAlgorithm que identifica el algoritmo utilizado
para cifrar - y sus parámetros asociados - este algoritmo es el
mismo para todos los destinatarios.
-
encryptedContent es el contenido cifrado. Este campo puede o no
estar presente, si no está presente, se intentará suplir
por otros medios.
Ejemplo de cifrado para un destinatario
Ejemplo de cifrado para varios destinatarios
Tipo de datos en ASN.1 RecipientInfo:
La información para cada destinatario se agrupa en una estructura
del tipo RecipientInfo:
RecipientInfo ::= SEQUENCE {
version Version,
issuerAndSerialNumber IssuerAndSerialNumber,
keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
encriptedKey EncryptedKey
}
EncryptedKey ::= OCTET STRING
Cuyo significado es:
version es la versión de la sintaxis que se está utilizando
issuerAndSerialNumber especifica el certificado del destinatario mediantela
información sobre la CA que ha expedido el certificado, es decir
su nombre y el número de serie de ese certificado
keyEncryptionAlgorithm identifica el algoritmo con el que se ha cifrado,
mediante la clave pública del destinatario, la clave de sesión.
encrytptedKey es la clave de sesión cifrada.
Proceso de cifrado de mensajes:
La entrada al proceso es el contenido que quiere ser metido en un "sobre",
especificamente la entrada puede ser también los bytes de contenido
de un tamaño definido codificados en BER contenidos en el subcampo
content
del valor ContentInfo de los datos a cifrar. Sólo los bytes
de contenido de la cofdificación BER se cifran, no los bytes identificativos
o los bytes de longitud, ya que no son representativos en este caso.
Cuando el tipo de datos a cifrar es data, sólo el valor
de los datos se cifra, esto tiene la ventaja de quue la longitud de los
datos no necesita ser conocida a priori en el proceso de cifrado.
Como hemos dicho antes, los bytes identificativos y los de longitud
no se encriptan; no por eso dejan de estar protegidos, ya que los bytes
de longitud están protegidos implícitamente por le proceso
de cifrado. Los identificativos no están protegidos, ya que pueden
ser recuperados por el contenido, asuminedo que el tipo de contenido determina
unívocamente los bytes identificativos. La protección de
los bytes identificativos y los de longitud implica el uso del tipo signed-and-enveloped-data
o que se utilicen el digested-data y después el enveloped-data.
Proceso de cifrado de la clave de sesión:
La entrada, lógicamente, es la llave de sesión que se ha
utilizado y la salida, la clave de sesión cifrada con la clave pública
del destinatario.
Tipo de contenido "signed-and-enveloped-data":
Este tipo consisten en un contenido cifrado de cualquier tipo, una llave
de sesión cifrada para uno o más destinatarios y los resúmenes
doblemente cifrados del mensaje para uno o más firmantes - doblemente
cifrados, ya que se cifran primero para firmar con la clave privada del
firmante y luego, se cifran con la llave de sesión del cifrado.
Así creamos un sobre - ya que el uso de la combinación del
cifrado del mensaje y el cifrado de la llave de sesión es un sobre
digital - firmado o autenticado - ya que el resumen encriptado del mensaje
con la clave privada del remitente es una firma digital -.
Cualquier tipo de contenido puede ser metido en un sobre y además
firmado por cualquier número de firmantes en paralelo.
El proceso con el que se crea este tipo de datos es el siguiente:
Se genera una llave de sesión aleatoria para un algoritmo de encriptación
en particular
Para cada destinatario se cifra la llave de sesión con su clave
píblica
Para cada destinatario, se junta la llave de sesión encriptada junto
con información adicional del destinatario en una estructura RecipientInfo.
Para cada firmante, se calcula un resumen del mensaje utilizando el algoritmo
que desee el firmante, si dos firmantes utilizan un mismo algoritmo, sólo
se calcula una sola vez.
Para cada firmante, el resumen y otra información adicional se cifra
con la clave pública propia de cada firmante para después
ser cifradda de nuevo con la llave de sesión utilizada.
Para cada firmante, el resumen doblemente cifrado se junta con otra información
adicional del firmante en una estructura de datos SignerInfo.
El contenido del mensaje se cifra con la llave de sesión.
Los resumenes del mensaje de todos los firmantes, las estructuras SignerInfo
y RecipientInfo de todos los destinatarios y firmantes se juntan
con el mensaje encriptado en una estructura SignedAndEnvelopedData.
El proceso a seguir por un destinatario es:
Verificar las firmas en dos pasos
-
Descifrar la llave de sesión utilizando su clave privada y descifrar
el contenido - es decir la información de los firmantes y el propio
mensaaje - con la llave de sesión
-
Descifrar los resumenes, utilizando primero la llave de sesión y
después la clave pública de cada firmante y confrontarlos
con un resumen calculado por el propio destinatario utilizando el mismo
algoritmo de resumen
Leer el mensaje previamente descifrado
Tipo de datos en ASN.1 SignedAndEnvelopedData:
La estructura de datos SignedAndEnvelopedData en ASN.1 es la que sigue:
SignedAndEnvelopedData ::= SEQUENCE {
version Version,
recipientInfos RecipientInfos,
digestAlgorithms DigestAlgorithmsIdentifiers,
encryptedContentInfo EncriptedContenInfo,
certificates
[0] IMPLICIT ExtendedCertificatesAndCertificates
OPTIONAL,
crls
[1] IMPLICIT CertificateRevocationLists
OPTIONAL,
signerInfos SignerInfos
}
Donde:
version es el número de versión que se utiliza en
la sintaxis.
recipientInfos es un conjunto de información de los destinatarios,
debe haber al menos uno.
digestAlgorithms es el conjunto de identificadores de algoritmos
que se han utilizado para resumir el mensaje.
encryptedContentInfo es el contenido del mensaje cifrado
certificates es un conjunto de certificados extendidos PKCS#6
y certificados X.509
crls es un conjunto de listas de certificados revocados
signerInfos es el conjunto de información sobre los firmantes,
debe haber al menos un elemento en esta lista. Los valores de esta estructura
son los mismos que en el tipo SignerInfo anteriormente explicado
exceptuando el campo encryptedDigest.
Proceso de resumen-cifrado:
La entrada de este proceso es la misma que la del proceso de resumen de
mensaje citado con anterioridad a este punto. Específicamente el
proceso puede tener dos pasos, el primero es como en el resumen del mensaje
y el segundo es el cifrado del resumen que ha salido del paso uno con la
llave de sesión. En este caso no hay una codificación en
BER entre los dos pasos, sino que el valor de salida del primer paso es
directamente el de entrada del segundo.
Tipo de contenido "digested-data":
Este tipo consiste en un contenido de cualquier tipo y su resumen correspondiente.
Su intención es la de garantizar la integridad del contenido y ser
entrada a procesos de crear objetos del tipo enveloped-data.
El proceso de creación es el siguiente:
Un resumen del contenido se calcula con el algoritmo que se desee.
El contenido y el resumen se juntan en una estructura del tipo DigestedData.
Tipo de datos en ASN.1 DigestedData:
DigestedData ::= SEQUENCE {
version Version,
digestAlgorithm digestAlgorithmIdentifier,
contentInfo ContentInfo,
digest Digest
}
Digest ::= OCTET STRING
Que significan:
version es la version de la sintaxis que se está utilizando
digestAlgorithm es el identificador del algoritmo con el que se
ha realizado el resumen
contentInfo es el contenido que se ha resumido
digest es el resumen del contenido
Tipo de contenido "encrypted-data":
Consiste en un contenido de cualquier tipo que se haya cifrado, distinto
al enveloped-data, no contiene ningúna referencia al destinatario
- ya que puede no existir - ni referencias a llaves de sesión. Las
medidas de seguridad en cuanto a llaves , se suponen tomadas por otros
medios. Su finalidad es la de encriptar contenido localmente, por eso la
llave de cifrado sea simplemente una password.
Tipo de datos en ASN.1 EncryptedData:
EncryptedData ::= SEQUENCE {
version Version,
encryptedContentInfo EncryptedContentInfo
}
Siendo :
version es la versión con la que se ha creado el objeto.
encryptedContentInfo es la información cifrada
Identificadores de objetos:
El estándar puesto en los RFC's define siete identificadores de
objetos : pkcs-7 , data, signedData, envelopedData,
signedAndEnvelopedData,
digestedData y encryptedData, explicados en este documento
siendo su estructura:
pkcs-7 OBJECT IDENTIFIER ::= { iso (1) member-body (2) US (840)
rsadsi (113549) pkcs (1) 7 }
data OBJECT IDENTIFIER ::= { pkcs-7 1}
signedData OBJECT IDENTIFIER ::= { pkcs-7 2}
envelopedData OBJECT IDENTIFIER ::= { pkcs-7 3}
signedAndEnvelopedData OBJECT IDENTIFIER ::= { pkcs-7 4}
digestedData OBJECT IDENTIFIER ::= { pkcs-7 5}
encrypedData OBJECT IDENTIFIER ::= { pkcs-7 6}
Ejemplos de algunos de estos identificadores de objetos:
OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
OBJECT IDENTIFIER envelopedData (1 2 840 113549 1 7 3)