RFC 7292

PKCS #12: Personal Information Exchange Syntax v1.1

πŸ“… published July 2014, from ietf

PKCS #12: Personal Information Exchange Syntax v1.1 πŸŽ€

Okay bestie, this is RFC 7292 πŸ’– It's an Informational doc, so it's not a Standards Track spec. It came out in July 2014 and sits in the ISSN series as ISSN 2070-1721. The authors are K. Moriarty, Ed. (EMC), M. Nystrom (Microsoft Corporation), and S. Parkinson, A. Rusch, and M. Scott (RSA). It doesn't list anything it obsoletes or updates, so it's just vibing solo ✨

Abstract 🌸

Okay so PKCS #12 v1.1 is a transfer syntax for personal identity info. That covers private keys, certificates, random secrets, and extensions πŸ” Any machine, app, browser, or Internet kiosk that supports it lets a user import, export, and use one set of their identity info. It also supports direct transfer under several privacy and integrity modes, which is giving secure and flexible energy πŸ’…

This document is a republication of PKCS #12 v1.1 from the RSA Laboratories' Public Key Cryptography Standard (PKCS) series. Publishing this RFC means change control moves to the IETF 🫢

IESG Note 🧚

The IESG (the IETF's steering group) thanks RSA Laboratories for handing over change control to the IETF πŸ™ They're also expecting enhancements that keep backward compatibility to show up in a future IETF Standards Track document. So stay tuned πŸ‘€

Status of This Memo πŸ¦‹

This one is not an Internet Standards Track spec. It's published for informational purposes only.

It is still an IETF product that reflects IETF community consensus. It got public review and was approved for publication by the IESG. Being approved by the IESG doesn't mean a doc qualifies for any level of Internet Standard, though. For that, see Section 2 of RFC 5741.

For the current status, any errata, and how to give feedback, check http://www.rfc-editor.org/info/rfc7292 πŸ”—

Copyright (c) 2014 IETF Trust and the people listed as document authors. All rights reserved πŸ’œ

This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info), as they stand on the publication date. Read them carefully, because they spell out your rights and restrictions for this document βš–οΈ Any Code Components pulled out of this doc have to include the Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions. They also come with no warranty, as described in the Simplified BSD License 🌈

Table of Contents πŸ“š

1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
  1.1.  Changes from PKCS #12 Version 1 . . . . . . . . . . . . .   4
2.  Definitions and Notation  . . . . . . . . . . . . . . . . . .   5
3.  Overview  . . . . . . . . . . . . . . . . . . . . . . . . . .   7
  3.1.  Exchange Modes  . . . . . . . . . . . . . . . . . . . . .   7
  3.2.  Mode Choice Policies  . . . . . . . . . . . . . . . . . .   8
  3.3.  Trusted Public Keys . . . . . . . . . . . . . . . . . . .   8
  3.4.  The AuthenticatedSafe . . . . . . . . . . . . . . . . . .   9
4.  PFX PDU Syntax  . . . . . . . . . . . . . . . . . . . . . . .  10
  4.1.  The AuthenticatedSafe Type  . . . . . . . . . . . . . . .  11
  4.2.  The SafeBag Type  . . . . . . . . . . . . . . . . . . . .  12
    4.2.1.  The KeyBag Type . . . . . . . . . . . . . . . . . . .  13
    4.2.2.  The PKCS8ShroudedKeyBag Type  . . . . . . . . . . . .  13
    4.2.3.  The CertBag Type  . . . . . . . . . . . . . . . . . .  13
    4.2.4.  The CRLBag Type . . . . . . . . . . . . . . . . . . .  14
    4.2.5.  The SecretBag Type  . . . . . . . . . . . . . . . . .  14
    4.2.6.  The SafeContents Type . . . . . . . . . . . . . . . .  14
5.  Using PFX PDUs  . . . . . . . . . . . . . . . . . . . . . . .  15
  5.1.  Creating PFX PDUs . . . . . . . . . . . . . . . . . . . .  15
  5.2.  Importing Keys, etc., from a PFX PDU  . . . . . . . . . .  16
6.  Security Considerations . . . . . . . . . . . . . . . . . . .  16
7.  Normative References  . . . . . . . . . . . . . . . . . . . .  17
Appendix A.  Message Authentication Codes (MACs)  . . . . . . . .  19
Appendix B.  Deriving Keys and IVs from Passwords and Salt  . . .  19
  B.1.  Password Formatting . . . . . . . . . . . . . . . . . . .  19
  B.2.  General Method  . . . . . . . . . . . . . . . . . . . . .  20
  B.3.  More on the ID Byte . . . . . . . . . . . . . . . . . . .  22
  B.4.  Keys for Password Integrity Mode  . . . . . . . . . . . .  22
Appendix C.  Keys and IVs for Password Privacy Mode . . . . . . .  22
Appendix D.  ASN.1 Module . . . . . . . . . . . . . . . . . . . .  24
Appendix E.  Intellectual Property Considerations . . . . . . . .  28
Appendix F.  Acknowledgments  . . . . . . . . . . . . . . . . . .  28
Appendix G.  About PKCS . . . . . . . . . . . . . . . . . . . . .  28

1. Introduction ✨

So this doc is the republication of PKCS #12 v1.1 from RSA Laboratories' PKCS series πŸ’« Publishing it as an RFC moves change control to the IETF. RSA and its parent company EMC still keep the right to keep publishing and distributing PKCS #12 v1.1 and its predecessors, which is a very fair flex πŸ’…

Everything in the body, except the Security Considerations section, is taken straight from the PKCS #12 v1.1 spec. The references and in-line cites were updated or added where it made sense, so they point to the newest docs as well as the ones that existed when PKCS #12 v1.1 first came out πŸ“š

PKCS #12 describes a transfer syntax for personal identity info, like private keys, certificates, random secrets, and extensions. Any machine, app, browser, or Internet kiosk that supports it lets a user import, export, and use one set of identity info 🧚

It also supports direct transfer of personal info under several privacy and integrity modes. The most secure modes need the source and destination platforms to have trusted public/private key pairs, one for digital signatures and one for encryption. There are also lower-security, password-based privacy and integrity modes for when trusted key pairs aren't around πŸ”

This standard should be amenable to both software and hardware implementations. Hardware can give you physical security in tamper-resistant tokens, like smart cards and Personal Computer Memory Card International Association (PCMCIA) devices πŸ“

Last one: this can be seen as building on PKCS #8 [15] [24]. It adds the important but supporting identity info next to the private keys, and it raises the security bar with public-key privacy and integrity modes πŸ¦‹

1.1. Changes from PKCS #12 Version 1 🌷

This doc moves PKCS #12 [16] into the IETF, with a few minor changes from the authors for this submission. Here's the tea β˜•

  • Added hash algorithms.
  • Brought in Technical Corrigendum #1, which makes some minor fixes to the ASN.1 syntax.
  • Removed 1024 (from the ASN.1 syntax) as an example of the iteration count.
  • Added a recommendation that the technique in Appendix B no longer be used for a specific mode (password privacy mode), and that techniques from PKCS#5 v2.1 be used instead.
  • Added comments and minor corrections to the ASN.1 module in Appendix C.
  • Removed the export regulations discussion from the former Appendix D.
  • Replaced RSA with EMC in the "Intellectual Property Considerations".
  • Made many changes and additions to the references.
  • Added a reference to NIST SP 800-132 for its recommendations on selecting the iteration count value for password integrity (part of dictionary-attack resistance).
  • Added a comment on the acronym expansion of PFX: the acronym is sometimes expanded as Personal Information Exchange.
  • In Appendix B, changed the phrase "no longer recommended" to "not recommended" in the following sentence, to clear up a question and make it clear the method was not recommended: "Note that this method for password privacy mode is no longer recommended."

2. Definitions and Notation ✨

okay bestie, let's get the vocab down first πŸŽ€

AlgorithmIdentifier: an ASN.1 type that identifies an algorithm (by an object identifier) plus any associated parameters. it's defined in [8] πŸ’…

ASN.1: Abstract Syntax Notation One, as defined in [2], [3], [4], and [5] 🧚

Attribute: an ASN.1 type that identifies an attribute type (by an object identifier) and an associated attribute value. the ASN.1 type Attribute is defined in [7] 🌸

Certificate: a digitally signed data unit that binds a public key to identity information. one specific format for identity certificates is defined in [8], and another format is described in [17] πŸŽ€

Certificate Revocation List (CRL): a digitally signed list of certificates that should no longer be honored, because the issuers or a higher authority revoked them. one format for CRLs is defined in [8] πŸ’€

ContentInfo: an ASN.1 type used to hold data that may have been cryptographically protected. this type is defined in [21] and [14] ✨

DER: Distinguished Encoding Rules, as defined in [6] πŸ¦‹

Destination platform: the ultimate, final target platform for the personal information coming from the source platform. even though certain information may be transported from the destination platform to the source platform, the ultimate target for personal information is always called the destination platform πŸ‘‘

DigestInfo: an ASN.1 type used to hold a message digest. this type is defined in [21] and [14] πŸ“

Encryption Key Pair (DestEncK): a public/private key pair used for the public-key privacy mode of this standard. the public half is called PDestEncK (TPDestEncK when you're emphasizing that the public key is "trusted"), and the private half is called VDestEncK πŸ”

Export time: the moment a user reads personal information from a source platform and transforms it into an interoperable, secure Protocol Data Unit (PDU) πŸ“€

Import time: the moment a user writes personal information from a Safe PDU to a destination platform πŸ“₯

Message Authentication Code (MAC): a type of collision-resistant, "unpredictable" function of a message and a secret key. MACs are used for data authentication and are kinda like secret-key digital signatures in lots of ways 🫢

Object Identifier: a sequence of integers that uniquely identifies an associated data object in a global name space run by a hierarchy of naming authorities. it's a primitive data type in ASN.1 🌈

PFX: the top-level exchange PDU defined in this standard. sometimes it gets expanded as Personal Information Exchange 🎁

Platform: a combo of machine, operating system, and applications software that the user exercises personal identity within. in this context, an application is software that uses personal information. two platforms differ if their machine types differ or if their applications software differs. there's at least one platform per user in multi-user systems πŸ–₯️

Protocol Data Unit (PDU): a sequence of bits in machine-independent format that makes up a message in a protocol πŸ“¦

Shrouding: encryption applied to private keys, possibly paired with a policy that keeps the plaintext of the key from ever being visible beyond a certain, well-defined interface 🫣

Signature Key Pair (SrcSigK): a platform-specific signature key pair used for the public-key integrity mode of this standard. the public half is called PSrcSigK (TPSrcSigK when you're emphasizing that the public key is "trusted"), and the private half is called VSrcSigK πŸ–‹οΈ

Source platform: the origin platform of the personal information that's ultimately meant for the destination platform. even though certain information may be transported from the destination platform to the source platform, the platform that originates the personal information is always called the source platform 🌟


3. Overview πŸ¦‹

3.1. Exchange Modes

okay so there are four combos of privacy modes and integrity modes πŸ’– the privacy modes use encryption to protect personal information from exposure, and the integrity modes protect personal information from tampering. without protection from tampering, an adversary could conceivably swap in invalid information for the user's personal information and the user would have no clue 😭

the privacy modes are:

  • Public-key privacy mode: personal information is enveloped on the source platform using a trusted encryption public key of a known destination platform (see Section 3.3). the envelope is opened with the corresponding private key πŸ”‘
  • Password privacy mode: personal information is encrypted with a symmetric key derived from a user name and a privacy password, as in [22] and [13]. if password integrity mode is used as well, the privacy password and the integrity password may or may not be the same πŸ™ˆ

the integrity modes are:

  • Public-key integrity mode: integrity is guaranteed through a digital signature on the contents of the PFX PDU, produced using the source platform's private signature key. the signature is verified on the destination platform using the corresponding public key (see Section 3.4) ✨
  • Password integrity mode: integrity is guaranteed through a Message Authentication Code (MAC) derived from a secret integrity password. if password privacy mode is used as well, the privacy password and the integrity password may or may not be the same πŸ’œ

3.2. Mode Choice Policies

all combinations of privacy and integrity modes are permitted in this standard. ngl, good security policy suggests avoiding certain practices, e.g., it can be unwise to transport private keys without physical protection when using password privacy mode, or when using public-key privacy mode with weak symmetric encryption 🚨

in general, the public-key modes for both privacy and integrity are preferable to the password modes (from a security viewpoint) πŸ‘‘ however, it's not always possible to use the public-key modes. for example, it may not be known at export time what the destination platform is. if that's the case, then the public-key privacy mode is precluded πŸ₯²

3.3. Trusted Public Keys

asymmetric key pairs can be used in this standard in two ways: public-key privacy mode and public-key integrity mode. for public-key privacy mode, an encryption key pair is required, and for public-key integrity mode, a signature key pair is required πŸ—οΈ

it may be appropriate for the keys discussed in this section to be platform-specific keys dedicated solely to transporting a user's personal information. whether or not that's the case, though, these keys shouldn't be confused with the user's personal keys that they want to transport from one platform to another. (those latter keys are stored within the PDU.) for public-key privacy mode, the private key from the encryption key pair is kept on the destination platform, where it's ultimately used to open a private envelope. the corresponding trusted public key is called TPDestEncK 🫧

for public-key integrity mode, the private key from the signature pair is kept on the source platform, where it's used to sign personal information. the corresponding trusted public key is called TPSrcSigK πŸ–ŠοΈ

for both uses of public/private key pairs, the public key from the key pair must be transported to the other platform such that it's trusted to have originated at the correct platform. judging whether a public key is trusted in this sense must ultimately be left to the user. there are a bunch of methods for making sure a public key is trusted 🌈

the processes of imbuing keys with trust and of verifying trustworthiness of keys are not discussed further in this document. whenever asymmetric keys come up in what follows, the public keys are assumed to be trusted 🫢

3.4. The AuthenticatedSafe

each compliant platform shall be able to import and export AuthenticatedSafe PDUs wrapped in PFX PDUs πŸŽ€

for integrity, the AuthenticatedSafe is either signed (if public-key integrity mode is used) or MACed (if password integrity mode is used) to produce a PFX PDU. if the AuthenticatedSafe is signed, it comes with a digital signature, produced on the source platform with a private signature key, VSrcSigK, that corresponds to a trusted public signature key, TPSrcSigK. TPSrcSigK must accompany the PFX to the destination platform, where the user can verify the trust in the key and verify the signature on the AuthenticatedSafe πŸ” if the AuthenticatedSafe is MACed, it comes with a MAC computed from a secret integrity password, salt bits, an iteration count, and the contents of the AuthenticatedSafe πŸ§‚

the AuthenticatedSafe itself is a sequence of ContentInfo values. some of them may be plaintext (data), and others may be either enveloped (if public-key privacy mode is used) or encrypted (if password privacy mode is used) 🎁 if the contents are enveloped, they're encrypted with a symmetric cipher under a freshly generated key, which is in turn encrypted with RSA asymmetric encryption. the RSA public key used to encrypt the symmetric key is called TPDestEncK and corresponds to an RSA private key, VDestEncK, on the destination platform. TPDestEncK needs to be trusted by the user when it's used at export time πŸ₯Ή if the contents are encrypted, they're encrypted with a symmetric cipher under a key derived from a secret privacy password, salt bits, and an iteration counter πŸ”

each ContentInfo contains an arbitrary collection of private keys, PKCS #8-shrouded private keys, certificates, CRLs, or opaque data objects, at the user's discretion, stored in values of type SafeContents 🌸

the raison d'etre for the unencrypted option is that some governments restrict certain uses of cryptography 🌍 having several parts in an AuthenticatedSafe keeps implementers' options open. for example, strong cryptography may be used to make PKCS #8-shrouded keys, but then those shrouded keys should not be further encrypted, because super-encryption can limit a product's exportability. the multi-part AuthenticatedSafe design permits this possibility 🧠

around the AuthenticatedSafe is the integrity-mode wrapper, which protects the entire contents of the AuthenticatedSafe (including unencrypted parts, if they're present). this is the reverse of the wrapping order in many protocols, where privacy is the outermost protection. that more-common wrapping order avoids signatures on encrypted data, which are undesirable under certain circumstances. however, those circumstances don't apply to this document, so it's preferable to protect the integrity of as much information as possible πŸ›‘οΈπŸ’…

4. PFX PDU Syntax ✨

okay so this section is the format that matches the data model we just went over, with wrappers for privacy and integrity πŸŽ€. It leans on PKCS #7 [14] [21] a LOT, so you should already be comfy with the terms in that doc πŸ’….

every mode of direct exchange uses the same PDU format, and ASN.1 plus BER-encoding is what keeps it platform independent 🌈.

there's only ONE ASN.1 export in this whole standard, and it's PFX πŸ‘‘. that's the outer integrity wrapper, and each PFX holds:

  1. A version indicator πŸ”’. It shall be v3 for this version of this document.
  2. A PKCS #7 ContentInfo, where the contentType is signedData in public-key integrity mode and data in password integrity mode.
  3. An optional MacData, which only shows up in password integrity πŸ”. If it's there, it holds a PKCS #7 DigestInfo with the MAC value, a macSalt, and an iterationCount. As Appendix B describes, the MAC key comes from the password, the macSalt, and the iterationCount. As Section 5 describes, the MAC is computed from the authSafe value and the MAC key via HMAC [11] [20]. Fun fact: the password and the MAC key are not actually present ANYWHERE in the PFX πŸ™ˆ. The salt and (to a certain extent) the iteration count thwart dictionary attacks against the integrity password. See NIST Special Publication 800-132 [12] for how to pick a reasonable iteration count.
PFX ::= SEQUENCE {
    version     INTEGER {v3(3)}(v3,...),
    authSafe    ContentInfo,
    macData     MacData OPTIONAL
}

MacData ::= SEQUENCE {
    mac         DigestInfo,
    macSalt     OCTET STRING,
    iterations  INTEGER DEFAULT 1
    -- Note: The default is for historical reasons and its
    --       use is deprecated.
}

4.1. The AuthenticatedSafe Type

as mentioned, the contentType field of authSafe shall be of type data or signedData 🫢. The content field of the authSafe shall contain a BER-encoded value of type AuthenticatedSafe, either directly (data case) or indirectly (signedData case). no cap, the nesting is kind of a lot 😭.

AuthenticatedSafe ::= SEQUENCE OF ContentInfo
    -- Data if unencrypted
    -- EncryptedData if password-encrypted
    -- EnvelopedData if public key-encrypted

an AuthenticatedSafe holds a sequence of ContentInfo values ✨. The content field of those ContentInfo values has either plaintext, encrypted, or enveloped data. For encrypted or enveloped data, the plaintext holds the BER-encoding of an instance of SafeContents. Section 5.1 of this document goes deeper into how values of type AuthenticatedSafe get built 🧚.

4.2. The SafeBag Type

okay the SafeContents type is made up of SafeBags πŸ“. Each SafeBag holds ONE piece of info (a key, a certificate, etc.), and it's identified by an object identifier.

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})
} -- This type is compatible with the X.500 type 'Attribute'

PKCS12AttrSet ATTRIBUTE ::= {
    friendlyName | -- from PKCS #9 [23]
    localKeyId,    -- from PKCS #9
    ... -- Other attributes are allowed
}

the optional bagAttributes field is the cute part πŸŽ€. It lets users give keys and stuff nicknames and IDs, so visual tools can show something meaningful to the human πŸ₯Ή.

six types of SafeBags are defined in this version of the doc πŸ‘‘:

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,
    ... -- For future extensions
}

as new bag types get recognized in future versions of this standard, the PKCS12BagSet may get extended 🌸.

4.2.1. The KeyBag Type

a KeyBag is a PKCS #8 PrivateKeyInfo πŸ”‘. Note that a KeyBag only contains ONE private key.

KeyBag ::= PrivateKeyInfo

4.2.2. The PKCS8ShroudedKeyBag Type

a PKCS8ShroudedKeyBag holds a private key that's been shrouded (aka hidden) according to PKCS #8 πŸ•ΆοΈ. Note that it only holds ONE shrouded private key.

PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo

4.2.3. The CertBag Type

a CertBag contains a certificate of a certain type πŸ“œ. Object identifiers are how we tell the different certificate types apart.

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

x509Certificate BAG-TYPE ::=
    {OCTET STRING IDENTIFIED BY {certTypes 1}}
    -- DER-encoded X.509 certificate stored in OCTET STRING
sdsiCertificate BAG-TYPE ::=
    {IA5String IDENTIFIED BY {certTypes 2}}
    -- Base64-encoded SDSI certificate stored in IA5String

CertTypes BAG-TYPE ::= {
    x509Certificate |
    sdsiCertificate,
    ... -- For future extensions
}

4.2.4. The CRLBag Type

a CRLBag contains a Certificate Revocation List (CRL) of a certain type 🚫. Same deal as before: object identifiers tell the different CRL types apart.

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

x509CRL BAG-TYPE ::=
    {OCTET STRING IDENTIFIED BY {crlTypes 1}}
    -- DER-encoded X.509 CRL stored in OCTET STRING

CRLTypes BAG-TYPE ::= {
    x509CRL,
    ... -- For future extensions
}

4.2.5. The SecretBag Type

each of the user's miscellaneous personal secrets lives in an instance of SecretBag 🀫. It holds an object identifier-dependent value, and note that a SecretBag only contains ONE secret.

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

SecretTypes BAG-TYPE ::= {
    ... -- For future extensions
}

implementers can add values to this set at their own discretion πŸ’œ.

4.2.6. The SafeContents Type

the sixth type of bag that can be held in a SafeBag is a SafeContents πŸͺ†. This recursive structure allows arbitrary nesting of multiple KeyBags, PKCS8ShroudedKeyBags, CertBags, CRLBags, and SecretBags inside the top-level SafeContents. Matryoshka vibes, periodt 🌈.

5. Using PFX PDUs

this section covers how PFX PDUs get created and used ✨.

5.1. Creating PFX PDUs

here are the steps for making PFX PDUs πŸ“:

  1. It's kinda clear from the ASN.1 how to make a bunch of instances of SafeContents, each with a bunch of (possibly nested) instances of SafeBag. So let's assume we've got instances SC_1, SC_2,..., SC_n of SafeContents. There can be a more or less arbitrary number of SafeContents instances in a PFX PDU 🧺. As step 2 shows, each instance can be encrypted (or not) separately.
  2. For each SC_i, depending on the encryption option you picked:
    • A. If SC_i is not to be encrypted, make a ContentInfo CI_i holding content type Data. The contents of the Data OCTET STRING shall be a BER-encoding of SC_i (including tag, length, and value octets).
    • B. If SC_i is to be encrypted with a password, make a ContentInfo CI_i of type EncryptedData. The encryptedContentInfo field of CI_i has its contentType field set to data and its encryptedContent field set to the encryption of the BER-encoding of SC_i (note that the tag and length octets shall be present) πŸ”’.
    • C. If SC_i is to be encrypted with a public key, make a ContentInfo CI_i of type EnvelopedData in essentially the same fashion as the EncryptedData ContentInfo was made in B πŸ—οΈ.
  3. Make an instance of AuthenticatedSafe by stringing together the CI_i's in a SEQUENCE 🧡.
  4. Make a ContentInfo T holding content type Data. The contents of the Data OCTET STRING shall be a BER-encoding of the AuthenticatedSafe value (including tag, length, and value octets) πŸ“¦.
  5. For integrity protection πŸ›‘οΈ:
    • A. If the PFX PDU is to be authenticated with a digital signature, make a ContentInfo C of type SignedData. The contentInfo field of the SignedData in C has T in it. C is the ContentInfo in the top-level PFX structure.
    • B. If the PFX PDU is to be authenticated with HMAC, then an HMAC with SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, or SHA-512/256 is computed on the contents of the Data in T (i.e., excluding the OCTET STRING tag and length bytes). This is exactly what would be initially digested in step 5A if public-key authentication were being used.

5.2. Importing Keys, etc., from a PFX PDU

importing from a PFX is basically the creation process run in reverse πŸ”„. In general, when an application imports keys and friends from a PFX, it should ignore any object identifiers it doesn't recognize. Sometimes it may be appropriate to alert the user that those unfamiliar OIDs are there πŸ‘€.

the application may want to take extra care when importing an item from the PFX would mean overwriting something that already exists locally 😬. How the app behaves can depend on what the item is. For example, a PKCS #8-shrouded private key and a CRL might need to be treated differently. Asking the user what to do with that item can be an appropriate move πŸ™‹.

6. Security Considerations

okay this part is SERIOUS 🚨. When using passwords in privacy or integrity mode, you have to remember that password-based cryptography is generally limited in the security it can give you. That's especially true for methods like the ones in this doc, where off-line password search is possible πŸ’€. Salt and iteration count can make attacks harder, but it's ESSENTIAL that passwords get picked well and that relevant guidelines (e.g., NIST SP 800-61-1) get followed πŸ”. It's also important that passwords stay well protected when they're stored 🫢.

when choosing a salt value in password privacy or integrity mode, the recommendations in Section 4 of PKCS #5 2.1 [13] [22] should be taken into account πŸ§‚. Ideally, the salt is as long as the output of the hash function being used and is made of randomly generated data 🎲✨.

7. Normative References ✨

okay bestie, this is the reading list πŸ“š these are the docs the spec leans on for its key stuff, so they're not optional vibes. here they are, slay them all πŸ’…

  • [1] Dobbertin, H., "The status of MD5 after a recent attack.", CryptoBytes Vol. 2, #2, 1996.
  • [2] ISO/IEC, "Information technology -- Abstract Syntax Notation One (ASN.1) -- Specification of basic notation", ISO/IEC 8824-1:2008, 2008.
  • [3] ISO/IEC, "Information technology -- Abstract Syntax Notation One (ASN.1) -- Information object specification", ISO/IEC 8824-2:2008, 2008.
  • [4] ISO/IEC, "Information technology -- Abstract Syntax Notation One (ASN.1) -- Constraint specification", ISO/IEC 88247-3:2008, 2008.
  • [5] ISO/IEC, "Information technology -- Abstract Syntax Notation One (ASN.1) -- Parameterization of ASN.1 specifications", ISO/IEC 8824-4:2008, 2008.
  • [6] ISO/IEC, "Information Technology - ASN.1 Encoding Rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER), and Distinguished Encoding Rules", ISO/IEC 8825-1:2008, 2008.
  • [7] ISO/IEC, "Information technology -- Open Systems Interconnection -- The Directory: Models", ISO/IEC 9594-2:1997, 1997.
  • [8] ISO/IEC, "Information technology -- Open Systems Interconnection -- The Directory: Authentication Framework", ISO/IEC 9594-8:1997, 1997.
  • [9] Microsoft, "PFX: Personal Exchange Syntax and Protocol Standard", ISO/IEC Version 0.020, January 1997.
  • [10] National Institute of Standards and Technology (NIST), "Secure Hash Standard", FIPS Publication 180-4, March 2012.
  • [11] National Institute of Standards and Technology (NIST), "The Keyed-Hash Message Authentication Code (HMAC)", FIPS Publication 198-1, July 2008.
  • [12] National Institute of Standards and Technology (NIST), "The Recommendation for Password-Based Key Derivation, Part 1: Storage Applications", NIST Special Publication 800-132, December 2010.
  • [13] RSA Laboratories, "PKCS #5: Password-Based Encryption Standard", PKCS Version 2.1, October 2012.
  • [14] RSA Laboratories, "PKCS #7: Cryptographic Message Syntax Standard", PKCS Version 1.5, November 1993.
  • [15] RSA Laboratories, "PKCS #8: Private-Key Information Syntax Standard", PKCS Version 1.2, November 1993.
  • [16] RSA Laboratories, "PKCS #12: Personal Information Exchange Syntax", PKCS Version 1.1, December 2012.
  • [17] Rivest, R. and B. Lampson, "SDSI - A Simple Distributed Security Infrastructure", 1996, <http://people.csail.mit.edu/rivest/sdsi10.html>.
  • [18] Turner, S. and L. Chen, "MD2 to Historic Status", RFC 6149, March 2011.
  • [19] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, April 1992.
  • [20] Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997.
  • [21] Kaliski, B., "PKCS #7: Cryptographic Message Syntax Version 1.5", RFC 2315, March 1998.
  • [22] Kaliski, B., "PKCS #5: Password-Based Cryptography Specification Version 2.0", RFC 2898, September 2000.
  • [23] Nystrom, M. and B. Kaliski, "PKCS #9: Selected Object Classes and Attribute Types Version 2.0", RFC 2985, November 2000.
  • [24] Turner, S., "Asymmetric Key Packages", RFC 5958, August 2010.
  • [25] Turner, S. and L. Chen, "Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms", RFC 6151, March 2011.

Appendix A. Message Authentication Codes (MACs) πŸ”

okay so a MAC is this special function πŸ¦‹ it takes a message (data bits) plus an integrity key. only someone who has BOTH the message and the integrity key can compute or check it. the whole security vibe rests on keeping that integrity key secret 🀫 in this standard, MACing is used in password integrity mode.

this doc uses a MAC called HMAC [11] [20], and it can be built on top of a bunch of different hash functions. heads up though, the specs in [20] and [11] are a little different from the one in [9] πŸ‘€ which hash function HMAC is built on gets named in the MacData, the thing that actually holds the MAC. for this version, the hash can be one of these: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, or SHA-512/256 [10]. as Appendix B.4 explains, that means the same hash has to be used to derive the MAC key in password integrity mode, and the MAC key has to be 160, 224, 256, 384, or 512 bits πŸŽ€

when password integrity mode secures a PFX PDU, an HMAC using SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, or SHA-512/256 gets computed over the BER-encoding of the contents of the content field of the authSafe field in the PFX PDU (see Section 5.1) πŸ’–


Appendix B. Deriving Keys and IVs from Passwords and Salt 🧚

⚠️ bestie, read this part first. this method for password privacy mode is not recommended and is deprecated for new usage πŸ’€ the procedures and algorithms in PKCS #5 v2.1 [13] [22] are what you should use instead. specifically, use PBES2 as the encryption scheme, with PBKDF2 as the key derivation function.

the method below is still used to generate the key in password integrity mode, so it's not totally dead 🌸

we're about to go over a general method for using a hash function to spit out different kinds of pseudorandom bits from a password and a string of salt bits. this method is used for password privacy mode and password integrity mode in this standard ✨

B.1. Password Formatting

the password-based encryption methods in PKCS #5 v2.1 treat passwords (and salt) as plain byte strings. the password-based encryption and password-based authentication methods in this version of the doc are similar πŸ“

here's the part that's left vague: exactly where the byte string for a password comes from. (this isn't an issue for salt, since salt is handed in as a password-based encryption or authentication parameter.) PKCS #5 v2.1 says: "[...] a password is considered to be an octet string of arbitrary length whose interpretation as a text string is unspecified. In the interest of interoperability, however, it is recommended that applications follow some common text encoding rules. ASCII and UTF-8 are two possibilities."

but in this spec, all passwords are made from BMPStrings with a NULL terminator πŸ’… each character in the BMPString gets encoded as 2 bytes in big-endian format (most-significant byte first). there are no Unicode byte order marks. the 2 bytes from the last character are followed by 2 extra bytes with the value 0x00.

let's do an example πŸ¦‹ if a user types the 6-character password "Beavis", the string PKCS #12 implementations should treat as the password is this 14-byte string:

0x00 0x42 0x00 0x65 0x00 0x61 0x00 0x76 0x00 0x69 0x00 0x73 0x00 0x00

B.2. General Method

okay so let H be a hash function built around a compression function f:

Z_2^u x Z_2^v -> Z_2^u

(basically, H has a chaining variable and an output that's u bits long, and the message going into the compression function of H is v bits.) here are the u and v values:

HASH FUNCTION     VALUE u        VALUE v
  MD2, MD5          128            512
    SHA-1           160            512
   SHA-224          224            512
   SHA-256          256            512
   SHA-384          384           1024
   SHA-512          512           1024
 SHA-512/224        224           1024
 SHA-512/256        256           1024

we also have r, the iteration count πŸ”

u and v are both multiples of 8, and so are the lengths of the password and salt strings (we call those p and s) and the number n of pseudorandom bits you need. u and v are also non-zero, obviously πŸ’œ

for security considerations on MD5 [19], check out [25] and [1], and for MD2, see [18] πŸ™ˆ

the following procedure can make pseudorandom bits for a particular "purpose", which is marked by a byte called "ID". we'll get to what that ID byte means later 🫢

  1. Construct a string, D (the "diversifier"), by concatenating v/8 copies of ID.
  2. Concatenate copies of the salt together to create a string S of length v(ceiling(s/v)) bits (the final copy of the salt may be truncated to create S). if the salt is the empty string, then so is S.
  3. Concatenate copies of the password together to create a string P of length v(ceiling(p/v)) bits (the final copy of the password may be truncated to create P). if the password is the empty string, then so is P.
  4. Set I=S||P to be the concatenation of S and P.
  5. Set c=ceiling(n/u).
  6. For i=1, 2, ..., c, do the following:
    • A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, H(H(H(... H(D||I))))
    • B. Concatenate copies of Ai to create a string B of length v bits (the final copy of Ai may be truncated to create B).
    • C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by setting I_j=(I_j+B+1) mod 2^v for each j.
  7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom bit string, A.
  8. Use the first n bits of A as the output of this entire process.

if this process is being used to generate a DES key, it should be used to create 64 random bits, and the key's parity bits should be set after those 64 bits have been produced. the same concerns apply to 2-key and 3-key triple-DES keys, to CDMF keys, and to any similar keys with parity bits "built into them" πŸ”‘

B.3. More on the ID Byte

this standard uses 3 different values for the ID byte we mentioned above 🌈

  1. If ID=1, then the pseudorandom bits being produced are to be used as key material for performing encryption or decryption.
  2. If ID=2, then the pseudorandom bits being produced are to be used as an IV (Initial Value) for encryption or decryption.
  3. If ID=3, then the pseudorandom bits being produced are to be used as an integrity key for MACing.

B.4. Keys for Password Integrity Mode

when password integrity mode protects a PFX PDU, a password and salt are used to derive a MAC key. just like with password privacy mode, the password is a Unicode string and the salt is a byte string. this standard doesn't prescribe any particular lengths for the password or the salt, but the general advice about passwords and salt in Appendix C applies here too πŸ’–

the hash function used to derive MAC keys is whatever hash function is going to be used for MACing. the MAC keys that come out have the same length as that hash function's output. in this version, SHA-1, SHA-224, SHA-256, SHA384, SHA-512, SHA-512/224, or SHA/512/256 can be used to do the MACing, so the MAC keys can be 160, 224, 256, 384, or 512 bits. check Appendix A for more on MACing πŸŽ€

Appendix C. Keys and IVs for Password Privacy Mode πŸŽ€

okay so bestie, remember how Appendix B started by saying this? Using this method for password privacy mode is not recommended πŸ™ˆ This spec for keys and IVs is only still here for backwards compatibility with PKCS #12 v1.0. It's giving vintage, not something you pick for new stuff πŸ’€

When password privacy mode encrypts a PFX PDU, we mix three things: a password (usually typed in by the user πŸ”), a salt, and an iteration parameter. Together they derive a key, plus an IV if one is needed ✨. The password is a Unicode string, so every character is 2 bytes πŸ“. The salt is a byte string, so you can use it directly as a sequence of bytes 🫢.

No length is prescribed for the password. Too short, though, and privacy might get compromised 😭. An application might totally require a user-entered privacy password for creating a PFX PDU to be longer than some specific length πŸ’….

No length is prescribed for the salt either πŸ™ˆ. Ideally, it's as long as the output of the hash function being used and made of completely random bits 🎲.

The iteration count is recommended to be 1024 or more. (See [22] and [13] for more information.) πŸ”’

PKCS #5's PBES1 encryption scheme gives you a bunch of algorithm identifiers for deriving keys and IVs. Here we specify a few more πŸ¦‹. They all use the procedure in Appendices B.2 and B.3 to build keys (and IVs, where needed). Like the names say, every object identifier below uses the hash function SHA-1 🌸.

pkcs-12PbeIds                    OBJECT IDENTIFIER ::= {pkcs-12 1}
pbeWithSHAAnd128BitRC4           OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1}
pbeWithSHAAnd40BitRC4            OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2}
pbeWithSHAAnd3-KeyTripleDES-CBC  OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
pbeWithSHAAnd2-KeyTripleDES-CBC  OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4}
pbeWithSHAAnd128BitRC2-CBC       OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5}
pbewithSHAAnd40BitRC2-CBC        OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6}

Each of those six PBE object identifiers has this ASN.1 type for its parameters 🧩:

pkcs-12PbeParams ::= SEQUENCE {
    salt        OCTET STRING,
    iterations  INTEGER
}

pkcs-12PbeParams holds the salt used to generate the key (and IV, if needed) and the number of iterations to run ✨.

Heads up: the first two algorithm identifiers (the RC4 ones) only derive keys. RC4 doesn't need an IV, so none gets derived 🌊.

This section is still around for two reasons πŸ‘‘. First, backwards compatibility, like the first paragraph of this section explained. Second, it's still used in password integrity mode. To stop using it there, the ASN.1 definitions need updates. This document recommends that future definitions of the PFX structure replace the existing MacData object (optionally present in password integrity mode) with a new object definition. That new object would hold a MAC based on the PKCS#5 [13] [22] PBMAC1 message authentication scheme. The change would simplify the requirements for key derivation functions used across all parts of the PFX structure 🫧.


Appendix D. ASN.1 Module 🧚

This appendix documents every ASN.1 type, value, and object set defined in this specification. It does that by providing an ASN.1 module called PKCS-12 πŸ“œ.

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

 -- PKCS #12 v1.1 ASN.1 Module
 -- Revised October 27, 2012

 -- This module has been checked for conformance with the ASN.1 standard
 -- by the OSS ASN.1 Tools

 DEFINITIONS IMPLICIT TAGS ::=

 BEGIN

 -- EXPORTS ALL
 -- All types and values defined in this module are exported for use
 -- in other ASN.1 modules.

 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)};

 -- ============================
 -- Object identifiers
 -- ============================


 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-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3}
 pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT 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}

 -- ============================
 -- The PFX PDU
 -- ============================

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

 MacData ::= SEQUENCE {
     mac        DigestInfo,
     macSalt    OCTET STRING,
     iterations INTEGER DEFAULT 1
     -- Note: The default is for historical reasons and its use is
     -- deprecated.
 }
 AuthenticatedSafe ::= SEQUENCE OF ContentInfo
     -- Data if unencrypted
     -- EncryptedData if password-encrypted
     -- EnvelopedData if public key-encrypted

 SafeContents ::= SEQUENCE OF SafeBag

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

 -- ============================
 -- Bag types
 -- ============================

 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,
     ... -- For future extensions
 }

 BAG-TYPE ::= TYPE-IDENTIFIER

 -- KeyBag
 KeyBag ::= PrivateKeyInfo

 -- Shrouded KeyBag
 PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo
 -- 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}}
     -- DER-encoded X.509 certificate stored in OCTET STRING
 sdsiCertificate BAG-TYPE ::=
     {IA5String IDENTIFIED BY {certTypes 2}}
     -- Base64-encoded SDSI certificate stored in IA5String

 CertTypes BAG-TYPE ::= {
     x509Certificate |
     sdsiCertificate,
     ... -- For future extensions
 }

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

 x509CRL BAG-TYPE ::=
     {OCTET STRING IDENTIFIED BY {crlTypes 1}}
     -- DER-encoded X.509 CRL stored in OCTET STRING

 CRLTypes BAG-TYPE ::= {
     x509CRL,
     ... -- For future extensions
 }

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

 SecretTypes BAG-TYPE ::= {
     ... -- For future extensions
 }

 -- ============================
 -- Attributes
 -- ============================
 PKCS12Attribute ::= SEQUENCE {
     attrId      ATTRIBUTE.&id ({PKCS12AttrSet}),
     attrValues  SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
 } -- This type is compatible with the X.500 type 'Attribute'

 PKCS12AttrSet ATTRIBUTE ::= {
     friendlyName |
     localKeyId,
     ... -- Other attributes are allowed
 }

 END

Appendix E. Intellectual Property Considerations βš–οΈ

EMC Corporation makes no patent claims on the general constructions described in this document, although specific underlying techniques may be covered 🧐.

RC2 and RC4 are trademarks of EMC Corporation ℒ️.

EMC Corporation makes no representations regarding intellectual property claims by other parties. Working out whether any of that applies is the responsibility of the user 🫑.

Appendix F. Acknowledgments 🫢

Huge thanks to Dan Simon of Microsoft Corporation and Jim Spring of Netscape Communications Corporation for helping with early drafts of this document πŸ’–. Especial thanks to Brian Beckman of Microsoft Corporation for writing the specification this document is based on πŸ‘‘.

Appendix G. About PKCS 🌈

The Public-Key Cryptography Standards are specifications produced by RSA Laboratories, in cooperation with secure systems developers worldwide, to speed up the deployment of public-key cryptography πŸ”‘. First published in 1991 after meetings with a small group of early adopters of public-key technology, the PKCS documents have become widely referenced and implemented. Contributions from the PKCS series have become part of many formal and de facto standards, including ANSI X9 documents, PKIX, SET, S/MIME, and SSL πŸ¦‹.

Further development of PKCS happens through the IETF. Suggestions for improvement are welcome πŸ’Œ.

Authors' Addresses πŸ’…

Kathleen M. Moriarty (editor)
EMC Corporation
176 South Street
Hopkinton, MA
United States

EMail: Kathleen.Moriarty@emc.com


Magnus Nystrom
Microsoft Corporation
1 Microsoft Way
Redmond, WA  98052
United States

EMail: mnystrom@microsoft.com


Sean Parkinson
RSA Security Inc.
345 Queen Street
Brisbane, QLD, 4000
Australia

EMail: Sean.Parkinson@rsa.com


Andreas Rusch
RSA Security Inc.
345 Queen Street
Brisbane, QLD, 4000
Australia

EMail: Andreas.Rusch@rsa.com


Michael Scott
RSA Security Inc.
345 Queen Street
Brisbane, QLD, 4000
Australia

EMail: Michael2.Scott@rsa.com
πŸ“¦ where this page comes from