PKCS #12. Sintaxis para el intercambio de Información personal

Tipos de Intercambio

Hay cuatro combinaciones de modos privados y modos de integridad según se utilicen políticas de llave pública o de passwords. Los modos privados utilizan el cifrado para proteger información personal de la exposición pública y los modos de integridad protegen la información personal de la falsificación de ésta.

Modos privados:
 

  • Modo privado de llave pública: La información personal es empaquetada y cifrada en la plataforma de origen usando una llave pública comprobada de la plataforma de destino. El paquete se abre con la correspondiente llave privada.
  • Modo privado de password: La información personal se cifra utilizando un login y un password.

  •  

     

    Modos de integridad:
     

  • Modo de integridad de llave pública: La integridad se garantiza mediante una firma digital en el contenido del PFX PDU - Protocolo de Unidad de Datos PFX- que se hace utilizando la llave privada de la plataforma de origen. Ésta firma se verificará en la plataforma de destino utilizando la clave pública correspondiente.
  • Modo de integridad con password: La integridad se garantiza utilizando un código de autentificación del mensaje - MAC - derivado del password de integridad de la plataforma origen.

  •  

     

    Para la buena utilización de los dos métodos basados en passwords, lo usual es que el password de integridad y de confidencialidad sean distintos.

    Las combinaciones de estos cuatro modos están puestas como buenas en el estándar. No obstante una buena política de seguridad nos sugiere que evitemos ciertas acciones, por ejemplo, puede ser imprudente el transportar claves privadas sin una protección física cuando utilizamos el modo privado de passwords o el modo privado de llave pública con criptografía débil. Aunque ésto sería lo deseable, algunos países -EEUU- no dejan enviar datos con cifrado fuerte al extrajero, no pudiendo hacer caso de éstos consejos por inflingir la ley.

    De todos modos, el uso de clave pública es preferible al de passwords en los dos casos - provecidad e integridad - aunque hay casos en los que no se puede utilizar, por ejemplo cuando enviamos información a la plataforma destino por primera vez, no tenemos nigún certificado de ella ni ella tiene ninguno nuestro, y seria una barbarie el enviarlo sin cifrar, por tanto se utilizan los passwords para hacer ese trabajo, la integridad de la información y su privacidad.

    Claves públicas fiables

    En este documento se utilizará la política de claves públicas para dos cosas, la integridad y la privacidad. Para la primera hace falta un par de llaves de firma y para la segunda un par de llaves de ecriptación. Éstas claves suelen ser las mismas, llamándose clave pública y clave privada a las dos llaves respectivamente.

    Es apropiado el utilizar llaves específicas para cada plataforma para el envio y recepción de datos de tipo personal, ya que no deben confundirse con las llaves pública y privada que el usuario en particular quiere enviar y/o recibir de una plataforam a otra, ya que éstas llaves están incluidas con el PDU.

    Para la confidencialidad en este modo - clave publica-privada - la llave privada del par debe estar en la plataforma destino y la pública en el origen, ya que utilizamos para cifrar siempre la clave pública del destinatario y para descifrar, nuestra propia clave privada, al cotrario pasa cuando hablamos de integridad - o autentificación - ya que el que lo firma, utiliza su clave privada entonces, utilizando la nomenclatura que habiamos usado antes, la clave privada estará en poder de la plataforma origen y la pública en la de destino. Como deducimos, para utilizar los dos modos -integridad y privacidad - la clave pública de la plataforma destino debe estar también en la de origen, para que la plataforma origen pueda cifrar - con la clave pública de la plataforma destino - y firmar - con su propia clave privada - .Ésta plataforma origen, tal como la plataforma destino le envie su clave pública, la deberá contrastar, como se explica en el documento PKCS #7.

    La Autentificación

    Cada plataforma debe ser capaz de importar y exportar PDU's de autentificación mediante el PFX PDU, a partir de ahora a este tipo de PDU's lo llamaremos Autentificación . Para integridad, la Autentificación podrá ser firmada - si se utiliza el modo de llaves - o MACeada - si se utiliza el modo de password - para producir un PFX PDU. Si la Autentificación está firmada, entonces , lógicamente, la acompañará una firma digital producida en la plataforma de origen con su llave privada, correspondiente a una clave de firma pública fiable - contrastada -. La clave pública de firma contrastada también estará incluida en el PFX para su posterior envío a la plataforma destino, donde el usuario podrá contrastarla por sus propios medios.Si la Autentificación está MACeada, o protegida con password, estará acompañada por un MAC - Message Autentication Code - conseguido a partir de un password secreto de integridad, la Autentificación en sí y varios campos más.

    La Autentificación consiste em una secuencia de valores tipo ContentInfo algunos de los cuales son texto plano - Tipo Data - , empaquetados - Tipo EnvelopedData - o cifrados - Tipo EncryptedData -. Si el tipo de datos es EnvelopedData, se genera una clave de sesión aleatoria, usada para cifrar los datos, que se cifra con la clave pública de la plataforma destino. La plataforma destino descifrará la clave de sesión y con ella descifrará el resto de los datos. Si el tipo de datos es cifrado como - EncryptedData - entonces se encriptan bajo una llave generada en base al password y otros campos mediante un algoritmo de cifrado simétrico.

    Cada valor ContentInfo puede contener una colección arbitraria de claves privadas, certificados tipo PKCS #8 conteniendo claves privadas, certificados, CRLs - Certificates Revocation Lists - o tipos opacos de objetos , todo esto se almacena en valores del tipo SafeContents. La razón de que existan en estos objetos datos no cifrados es por lo que ya comentabamos antes, por las restricciones que algunos paises hacen hacia la criptografía de esto que se creen la Autentificación multi-part.
     

    Sintaxis del PFX PDU

    Este formato corresponde a un modelo de datos con envolturas para la privacidad y la integridad de los datos. Todos los modos de intercambio directo utilizan el mismo formato PDU, ASN.1 y codificación BER para asegurar la independencia de plataformas. El PFX es un tipo de datos ASN.1 para exportar. Ésta es la envoltura exterior para la integridad. Las partes del PFX son :
  • Indicador de versión con el que se hace el PFX
  • Un PKCS #7 ContentInfo conteniendo SignedData si utilizamos modos de integridad de clave pública o Data si utilizamos modo de integridad de password.
  • Un campo opcional de MacData que estará presente si utilizamos integridad por password. Este objeto contendrá un PKCS #7 DigestInfo - Resumen- que contiene el valor del MAC, un campo tipo macSalt y un campo tipo interationMac.
  • Objeto tipo PFX en ASN.1

    PFX ::= SEQUENCE {
        version     INTEGER {v3(3)}(v3,...),
        authSafe    ContentInfo,
        macData     MacData OPTIONAL
        }
    MacData ::= SEQUENCE {
        mac         DigestInfo,
        macSalt     OCTET STRING,
        iterations  INTEGER DEFAULT 1
        -- El valor default está por razones históricas y no se usa. Un valor mayor, como 1024 es recomendable
        }

    El tipo Autentificación -AutenticatedSafe -

    El campo contentType de authSafe estará formado por tipos data o signedData. El campo content de authSafe estara directa - caso de que sea data - o indirectamente - en el caso de que sea signedData - conteniendo el valor codificado en BER del tipo AuthenticatedSafe.

    AuthenticatedSafe ::= SEQUENCE OF ContentInfo
        -- Data si no utilizamos el cifrado
        -- EncryptedData si utilizamos el cifrado por password
        -- EnvelopedData si utilizamos el cifrado por clave pública

    Un tipo AutenticatedSafe contiene un secuencia de valores del tipo ContentInfo. El campo content de estos valores ContentInfo pueden contener Data, EncryptedData o EnvelopedData. En el caso de que utilicemos datos empaquetados -enveloped - o cifrados -encrypted - , el texto en claro de los datos contendrá la codificación BER de los SafeContents o contenidos seguros.

    El tipo SafeBag

    El tipo SafeContents está formado por varios SafeBags - Bolsas seguras - que pueden contener sólo una parte de la información, es decir, un certificado, una clave , ... - que será identificada por un identificador de objeto.
    SafeContents ::= SEQUENCE OF SafeBag

    SafeBag ::= SEQUENCE {
        bagId BAG-TYPE.&id ({PKCS12BagSet})
        bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
        bagAttributes SET OF PKCS12Attribute OPTIONAL
        }

    PKCS12Attribute ::= SEQUENCE {
        attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
        attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
        }
        -- Este tipo es compatible con los tipos Atributo del X.500

    PKCS12AttrSet ATTRIBUTE ::= {
        friendlyName | -- de los PKCS #9
        localKeyId, -- de los PKCS #9
        ... -- Otros atributos están permitidos
        }

    Los atributos opcionales de SafeBag permite a los usuarios el asignar alias - o nicks - o identificadores a las llaves , ...  y permite a las herramientas visuales el enseñar cadenas conocidas de cada tipo al usuario.
    Hay 6 tipos de bolsas seguras:

    bagtypes OBJECT IDENTIFIER ::= {pkcs-12 10 1}
    BAG-TYPE ::= TYPE-IDENTIFIER
    keyBag BAG-TYPE ::= {KeyBag IDENTIFIED BY {bagtypes 1}}
    pkcs8ShroudedKeyBag BAG-TYPE ::= {PKCS8ShroudedKeyBag IDENTIFIED BY {bagtypes 2}}
    certBag BAG-TYPE ::= {CertBag IDENTIFIED BY {bagtypes 3}}
    crlBag BAG-TYPE ::= {CRLBag IDENTIFIED BY {bagtypes 4}}
    secretBag BAG-TYPE ::= {SecretBag IDENTIFIED BY {bagtypes 5}}
    safeContentsBag BAG-TYPE ::= {SafeContents IDENTIFIED BY {bagtypes 6}}

    PKCS12BagSet BAG-TYPE ::= {
        keyBag |
        pkcs8ShroudedKeyBag |
        certBag |
        crlBag |
        secretBag |
        safeContentsBag,
        ... -- Para futuras ampliaciones
        }

    El tipo KeyBag

    Una KeyBag - o bolsa de llave - es un objeto tipo PKCS#8 PrivateKeyInfo que únicamente contiene una llave privada

    KeyBag ::= PrivateKeyInfo

    El tipo pkcs8ShroudedKeyBag

    Esta bolsa contiene una llave privada, que se ha sido envuelta de acuerdo con las normas de los PKCS#8. Sólo contiene una clave privada.

    PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo

    El tipo certBag

    Una bolsa de este tipo contiene certificados de un tipo concreto. Los identificadores de objetos se usan para distinguir entre certificados de varios tipos.
    CertBag ::= SEQUENCE {
        certId BAG-TYPE.&id ({CertTypes}),
        certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
        }

        x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}}
        -- Codificación en DER de un certificado X.509 que se guarda en OCTET STRING
        sdsiCertificate BAG-TYPE ::= {IA5String IDENTIFIED BY {certTypes 2}}
        -- Codificación en Base64 de certificados SDSI guardado en IA5String CertTypes

    BAG-TYPE ::= {
        x509Certificate |
        sdsiCertificate,
        ... -- Para futuras ampliaciones
       }

    El tipo CRLBag

    Contiene Listas de certificados revocados de un tipo en concreto. Los identificadores nos indican de que tipo es.
    CRLBag ::= SEQUENCE {
        crlId BAG-TYPE.&id ({CRLTypes}),
        crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId})
        }

    x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}
    -- codificación en DER de un lista de certificados revocados X.509 guardada en OCTET STRING

    CRLTypes BAG-TYPE ::= {
        x509CRL,
        ... -- Para futuras ampliaciones
       }

    El tipo SecretBag

    Contiene información que el usuario no quiere que se conozca. Cada información se contendrá en una instancia de éste tipo que ocntendrá también un identificador dependiente de la información a la que identifique. En una bolsa de este tipo sólo se podrá tener uno y solo un secreto.
    SecretBag ::= SEQUENCE {
        secretTypeId BAG-TYPE.&id ({SecretTypes}),
        secretValue [0] EXPLICIT BAG-TYPE.&Type ({SecretTypes}{secretTypeId})
        }

    SecretTypes BAG-TYPE ::= {
        ... -- Para futuras ampliaciones
        }

    El tipo SafeContents

    Este sexto tipo de bolsa puede contener una SafeBag como una SafeContents. Este estructura recursiva permite anidar multiples KeyBags, PKCS8ShroudedKeyBags, CertBags, CRLBags y SecretBags sin el encabezamiento de SafeContents.

    El uso de PFX PDUs

    Aqui describiremos la creación y el uso de estos objetos

    Creación de PFX PDUs

    1. Esta claro desde las representaciones en ASN.1 anteriores el cómo hacer un número determinado de instancias del tipo SafeContents, cada una conteniendo un numero de instancias de SafeBag que podrán ser o no anidadas. Asumimos entonces, un número de instancias SC1, SC2, ... , SCN de Contenidos Seguros - SafeContents -.. Como se puede ver, en un PFX PDU pueden haber más o menos instancias de SafeContents según creamos conveniente al crearlo.
    2. Para cada intancia de SafeContents SCi, dependiendo de la elección que hayamos elegido para cifrarlo tenemos:
    3. Crearemos una instancia de AuthenticatedSafe juntando los CI's en una SEQUENCE -secuencia de bytes -.
    4. Hacemos un ContentInfo T de tipo Data en cuyo campo Data OCTET STRING estará la codificación en BER del valor creado en el paso anterior AuthenticatedSafe.
    5. Para proteger la integridad:

    Importación de información desde un PFX PDU

    La importación se hace, basicamente, utilizando el proceso inverso al que hemos utilizado al creal el PFX PDU. En general, cuando las aplicaciones importan datos desde un PFX, ignoran los identificadores de objetos que desconocen, y por tanto, los objetos en sí, debiéndose , a veces, que advertir al usuario de la presencia de los campos.

    Debemos tener mucho cuidado cuando la aplicación necesita machacar datos que ya estaban localmente instalados, ya que un usuario puede tener varios tipos de información sensible de ser utilizada - certificados, llaves ... -. La aplicación deberá saber el trato que se le ha de hacer a determinados datos, ya que se deberán tratar de forma diferente según el tipo que sean - por ejemplo, no es lo mismo machacar una llave privada que una lista de certificados revocados -. Un comportamiento apropiado de la aplicación sería alertarnos de qué es lo que se va a sobreescribir y darnos a nosotros la opción de sobreescribirlo o no.

    Message Authentication Codes (MAC's)

    Un MAC es un tipo de función especial que se aplica a un mensaje en base a una llave de integridad -password-. Ésta puede ser calculada o verificada solo por el que posea el mensaje -cifrado- y el password. Como cualquier password, este método de seguridad se basa en el secreto del password.

    Aquí se utiliza una función en particular llamada HMAC, o funcion hash con MAC, que puede ser utilizada con varias funciones de hash. La función HMAC se basa en su identificador en el campo MacData que contiene el MAC en sí. Para la versión en la que se basa este documento se utiliza la función SHA-1; esto implica que SHA-1 se aplica para derivar el password -MAC key- en si mismo utilizando el modo de integridad por password y que el password tiene 160 bits.

    Cuando se utiliza el modo de integridad por password para proteger un PFX PDU, la función SHA-1 HMAC se calcula en base a la codificación en BER del contenido del campo content del campo authSafe del PFX PDU.

    Formato en ASN.1 de un PKCS #12 - PFX PDU - completo

    PKCS-12 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-12(12) modules(0) pkcs-12(1)}

    DEFINITIONS IMPLICIT TAGS ::=

    BEGIN

    -- EXPORTS ALL
    -- Todos los tipos y valorres definidos en este módulo son exportados para su uso en otros módulos ASN.1

    IMPORTS

    informationFramework
        FROM UsefulDefinitions {joint-iso-itu-t(2) ds(5) module(1) usefulDefinitions(0) 3}

    ATTRIBUTE
        FROM InformationFramework informationFramework

    ContentInfo, DigestInfo
        FROM PKCS-7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7) modules(0) pkcs-7(1)}

    PrivateKeyInfo, EncryptedPrivateKeyInfo
        FROM PKCS-8 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-8(8) modules(1) pkcs-8(1)}

    pkcs-9, friendlyName, localKeyId, certTypes, crlTypes
        FROM PKCS-9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) modules(0) pkcs-9(1)};

    -- Identificadores de Objetos
    rsadsi OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549)}
    pkcs OBJECT IDENTIFIER ::= {rsadsi pkcs(1)}
    pkcs-12 OBJECT IDENTIFIER ::= {pkcs 12}
    pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1}
    pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1}
    pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2}
    pbeWithSHAAnd3-KeyTripleDES-CBCOBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
    pbeWithSHAAnd2-KeyTripleDES-CBCOBJECT IDENTIFIER ::= {pkcs-12PbeIds 4}
    pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5}
    pbewithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6}

    bagtypes OBJECT IDENTIFIER ::= {pkcs-12 10 1}

    -- El PFX PDU en sí

    PFX ::= SEQUENCE {
        version INTEGER {v3(3)}(v3,...),
        authSafe ContentInfo,
        macData MacData OPTIONAL
        }

    MacData ::= SEQUENCE {
        mac DigestInfo,
        macSalt OCTET STRING,
        iterations INTEGER DEFAULT 1
        -- El valor por defecto es por razones históricas, que hoy por hoy está en desuso, se recomienda un valor mayor como 1024
       }

    AuthenticatedSafe ::= SEQUENCE OF ContentInfo
        -- Data si no está cifrado
        -- EncryptedData si está protegido por password
        -- EnvelopedData si está protegido mediante llave pública

    SafeContents ::= SEQUENCE OF SafeBag

    SafeBag ::= SEQUENCE {
        bagId BAG-TYPE.&id ({PKCS12BagSet}),
        bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
        bagAttributes SET OF PKCS12Attribute OPTIONAL
        }

    -- Tipos de Bolsas

    keyBag BAG-TYPE ::= {KeyBag IDENTIFIED BY {bagtypes 1}}
    pkcs-8ShroudedKeyBag BAG-TYPE ::= {PKCS8ShroudedKeyBag IDENTIFIED BY {bagtypes 2}}
    certBag BAG-TYPE ::= {CertBag IDENTIFIED BY {bagtypes 3}}
    crlBag BAG-TYPE ::= {CRLBag IDENTIFIED BY {bagtypes 4}}
    secretBag BAG-TYPE ::= {SecretBag IDENTIFIED BY {bagtypes 5}}

    safeContentsBag BAG-TYPE ::= {SafeContents IDENTIFIED BY {bagtypes 6}}
    PKCS12BagSet BAG-TYPE ::= {
        keyBag |
        pkcs8ShroudedKeyBag |
        certBag |
        crlBag |
        secretBag |
        safeContentsBag,
        ... -- For future extensions
        }

    BAG-TYPE ::= TYPE-IDENTIFIER

    -- Tipo de bolsa KeyBag
    KeyBag ::= PrivateKeyInfo

    -- Tipo de bolsa Shrouded KeyBag
    PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo

    -- Tipo de bolsa CertBag
    CertBag ::= SEQUENCE {
        certId BAG-TYPE.&id ({CertTypes}),
        certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
        }

    x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}}
    -- La codificación DER de un certificado X.509 se guarda en OCTET STRING

    sdsiCertificate BAG-TYPE ::= {IA5String IDENTIFIED BY {certTypes 2}}
    -- La codificación en Base64 de un certificado SDSI se guarda en IA5String

    CertTypes BAG-TYPE ::= {
        x509Certificate |
        sdsiCertificate,
        ...
        -- Para futuras extensiones
       }

    -- Tipo de bolsa CRLBag

    CRLBag ::= SEQUENCE {
        crlId BAG-TYPE.&id ({CRLTypes}),
        crltValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId})
        }

    x509CRL BAG-TYPE ::={
        OCTET STRING IDENTIFIED BY {certTypes 1}
        }
    -- La codificación DER de una lista de certificados revocados X.509 se guarda en OCTET STRING
        CRLTypes BAG-TYPE ::= {
        x509CRL,
        ...
        -- para futuras extensiones
        }

    -- Tipo de bolsa Secret Bag
    SecretBag ::= SEQUENCE {
        secretTypeId BAG-TYPE.&id ({SecretTypes}),
        secretValue [0] EXPLICIT BAG-TYPE.&Type ({SecretTypes}{@secretTypeId})
        }

    SecretTypes BAG-TYPE ::= {
        ...
        -- para futuras extensiones
        }

    -- Atributos
    PKCS12Attribute ::= SEQUENCE {
        attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
        attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
        }
    -- Este tipo es compatible con el tipo de atributo X.500

    PKCS12AttrSet ATTRIBUTE ::= {
        friendlyName |
        localKeyId,
        ...
        -- Se permiten otros tipos de atributos
        }

    END