RFC 2511

Internet X.509 Certificate Request Message Format

πŸ“… published March 1999, from ietf

RFC 2511: Internet X.509 Certificate Request Message Format πŸŽ€

Bestie, this one is a Standards Track doc from March 1999 πŸ’…. It was written by M. Myers (VeriSign), C. Adams (Entrust Technologies), D. Solo (Citicorp), and D. Kemp (DoD) πŸ‘‘. It's part of the Network Working Group series, numbered Request for Comments: 2511. Its title block doesn't list any RFCs it obsoletes or updates, so nothing is being replaced or changed according to that block ✨.

Status of this Memo πŸ“œ

This document specifies an Internet standards track protocol for the Internet community, and it's asking for discussion and suggestions for improvements 🫢. For the standardization state and status of this protocol, check the current edition of the "Internet Official Protocol Standards" (STD 1) πŸ”. Distribution of this memo is unlimited 🌈.

Copyright (C) The Internet Society (1999). All Rights Reserved.

1. Abstract ✨

Okay so this doc describes the Certificate Request Message Format, or CRMF for short πŸ’–. It's the syntax used to send a request for a certificate to a Certification Authority (CA), and that might happen through a Registration Authority (RA) too πŸŽ€. The whole point is X.509 certificate production πŸ”₯. The request will typically include a public key and some associated registration information 🌸.

The key words "MUST", REQUIRED, "SHOULD", RECOMMENDED, and "MAY" in this document (in uppercase, as shown) are to be interpreted as described in RFC 2119 🧚. Yes, those capital words are doing real work, so don't sleep on them πŸ’€.

2. Overview 🌟

Building a certification request is a little process with four steps, and it's giving recipe energy πŸ“:

  • a) A CertRequest value gets constructed. This value may include the public key, all or a portion of the end-entity's (EE's) name, other requested certificate fields, and additional control information related to the registration process πŸ’….
  • b) A proof of possession value (for the private key that matches the public key a certificate is being requested for) may be calculated across the CertRequest value πŸ”.
  • c) Additional registration information may be combined with the proof of possession value and the CertRequest structure to form a CertReqMessage 🧩.
  • d) The CertReqMessage gets securely communicated to a CA. Specific means of secure transport are beyond the scope of this specification πŸ™ˆ.

3. CertReqMessage Syntax πŸ’œ

A certificate request message is made up of the certificate request, an optional proof of possession field, and an optional registration information field. Very customizable, very iconic πŸ‘‘.

CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg

CertReqMsg ::= SEQUENCE {
    certReq   CertRequest,
    pop       ProofOfPossession  OPTIONAL,
    -- content depends upon key type
    regInfo   SEQUENCE SIZE(1..MAX) of AttributeTypeAndValue OPTIONAL }

Okay, the proof of possession field exists to show that the entity tied to the certificate actually has the matching private key πŸ”‘. It may be calculated across the contents of the certReq field, and its structure and content change depending on the public key algorithm type and operational mode πŸ¦‹.

The regInfo field SHOULD only contain supplementary information related to the context of the certification request, and only when that information is needed to fulfill the request πŸ’…. This information MAY include subscriber contact information, billing information, or other ancillary information useful to fulfilling the certification request 🌈.

Information that's directly related to certificate content SHOULD be included in the certReq content πŸŽ€. Heads up though: if RAs add extra certReq content, that can invalidate the pop field 😭. So data meant for certificate content MAY be provided in regInfo instead ✨.

See Section 8 and Appendix B for example regInfo contents πŸ“–.

4. Proof of Possession (POP) πŸ”

Here's the big deal: to stop certain attacks, and to let a CA/RA properly check that the binding between an end entity and a key pair is valid, the PKI management operations in this spec let an end entity prove it has possession of (aka can actually use) the private key for the public key it's requesting a certificate for 🫢. A given CA/RA can pick how it enforces POP, like out-of-band procedural means or the CRMF in-band message, and that's a policy call πŸ’Ό.

But here's the tea β˜•: it is mandated that CAs/RAs MUST enforce POP by some means. Why? Because there are currently a bunch of non-PKIX operational protocols in use (various electronic mail protocols are one example) that don't explicitly check the binding between the end entity and the private key 😬. Until operational protocols that do verify that binding (for signature, encryption, and key agreement key pairs) exist and are everywhere, the binding can only be assumed to have been verified by the CA/RA 🧐. So if the CA/RA doesn't verify the binding, certificates in the Internet Public-Key Infrastructure end up being somewhat less meaningful πŸ’€.

POP works differently depending on the type of key the certificate is requested for. If a key can be used for multiple purposes (like an RSA key), then any of the methods MAY be used 🌸.

This spec allows for cases where POP gets validated by the CA, the RA, or both πŸ’–. Some policies may require the CA to verify POP during certification. In that case, the RA MUST forward the end entity's CertRequest and ProofOfPossession fields unaltered to the CA, and as an option MAY also verify POP πŸŽ€. If the CA isn't required by policy to verify POP, then the RA SHOULD forward the end entity's request and proof unaltered to the CA, as above 🧚. If that isn't possible (for example, because the RA verifies POP by an out-of-band method), then the RA MAY attest to the CA that the required proof has been validated πŸ¦‹. And if the CA uses an out-of-band method to verify POP (such as physical delivery of CA-generated private keys), then the ProofOfPossession field isn't used at all πŸ“.

4.1 Signature Keys ✍️

For signature keys, the end entity can sign a value to prove it has the private key πŸ’….

4.2 Key Encipherment Keys πŸ”

For key encipherment keys, the end entity can give the private key to the CA/RA, or it can be required to decrypt a value in order to prove possession of the private key πŸ—οΈ. Decrypting a value can be done either directly or indirectly ✨.

The direct method is for the RA/CA to issue a random challenge that needs an immediate response from the end entity πŸ”₯.

The indirect method is to issue a certificate that's encrypted for the end entity, and then have the end entity show it can decrypt that certificate in a confirmation message 🫢. This lets a CA issue a certificate in a form that can only be used by the intended end entity πŸ‘‘.

4.3 Key Agreement Keys 🀝

For key agreement keys, the end entity can use any of the three methods given in Section 5.2 for encryption keys πŸ’–. For the direct and indirect methods, the end entity and the PKI management entity (i.e., CA or RA) must establish a shared secret key so the end entity can prove it has the private key (i.e., to decrypt the encrypted certificate or to build the response to the issued challenge) 🌈.

Note that this doesn't have to restrict which keys a given CA can certify. In particular, for Diffie-Hellman keys, the end entity can freely choose its algorithm parameters, as long as the CA can generate a short-term (or one-time) key pair with the appropriate parameters when needed 🧠.

The end entity may also MAC the certificate request (using a shared secret key derived from a Diffie-Hellman computation) as a fourth alternative for demonstrating POP πŸŽ€. This option may only be used if the CA already has a DH certificate that the end entity knows about, and if the EE is willing to use the CA's DH parameters πŸ™ˆ.

4.4 Proof of Possession Syntax 🧾

Here's the ASN.1 for all of this, so get ready πŸ€“:

ProofOfPossession ::= CHOICE {
    raVerified        [0] NULL,
    -- used if the RA has already verified that the requester is in
    -- possession of the private key
    signature         [1] POPOSigningKey,
    keyEncipherment   [2] POPOPrivKey,
    keyAgreement      [3] POPOPrivKey }

POPOSigningKey ::= SEQUENCE {
    poposkInput         [0] POPOSigningKeyInput OPTIONAL,
    algorithmIdentifier     AlgorithmIdentifier,
    signature               BIT STRING }
    -- The signature (using "algorithmIdentifier") is on the
    -- DER-encoded value of poposkInput.  NOTE: If the CertReqMsg
    -- certReq CertTemplate contains the subject and publicKey values,
    -- then poposkInput MUST be omitted and the signature MUST be
    -- computed on the DER-encoded value of CertReqMsg certReq.  If
    -- the CertReqMsg certReq CertTemplate does not contain the public
    -- key and subject values, then poposkInput MUST be present and
    -- MUST be signed.  This strategy ensures that the public key is
    -- not present in both the poposkInput and CertReqMsg certReq
    -- CertTemplate fields.

POPOSigningKeyInput ::= SEQUENCE {
    authInfo            CHOICE {
        sender              [0] GeneralName,
        -- used only if an authenticated identity has been
        -- established for the sender (e.g., a DN from a
        -- previously-issued and currently-valid certificate)
        publicKeyMAC        PKMACValue },
        -- used if no authenticated GeneralName currently exists for
        -- the sender; publicKeyMAC contains a password-based MAC
        -- on the DER-encoded value of publicKey
    publicKey           SubjectPublicKeyInfo }  -- from CertTemplate

PKMACValue ::= SEQUENCE {
   algId  AlgorithmIdentifier,
   -- the algorithm value shall be PasswordBasedMac
   --     {1 2 840 113533 7 66 13}
   -- the parameter value is PBMParameter
   value  BIT STRING }

POPOPrivKey ::= CHOICE {
    thisMessage       [0] BIT STRING,
    -- posession is proven in this message (which contains the private
    -- key itself (encrypted for the CA))
    subsequentMessage [1] SubsequentMessage,
    -- possession will be proven in a subsequent message
    dhMAC             [2] BIT STRING }
    -- for keyAgreement (only), possession is proven in this message
    -- (which contains a MAC (over the DER-encoded value of the
    -- certReq parameter in CertReqMsg, which must include both subject
    -- and publicKey) based on a key derived from the end entity's
    -- private DH key and the CA's public DH key);
    -- the dhMAC value MUST be calculated as per the directions given
    -- in Appendix A.

SubsequentMessage ::= INTEGER {

    encrCert (0),
    -- requests that resulting certificate be encrypted for the
    -- end entity (following which, POP will be proven in a
    -- confirmation message)
    challengeResp (1) }
    -- requests that CA/RA engage in challenge-response exchange with
    -- end entity in order to prove private key possession

Last bit: protocols that use this spec are expected to include the confirmation and challenge-response messages needed for a complete protocol 🌟. Keep going, we're just getting warmed up πŸ’…βœ¨

4.4.1. Use of Password-Based MAC ✨

Okay bestie, this part is all about proving that a request really came from who it says it did πŸ”πŸ’– The following algorithm SHALL be used when publicKeyMAC is used in POPOSigningKeyInput to prove the authenticity of a request.

PBMParameter ::= SEQUENCE {
      salt                OCTET STRING,
      owf                 AlgorithmIdentifier,
      -- AlgId for a One-Way Function (SHA-1 recommended)
      iterationCount      INTEGER,
      -- number of times the OWF is applied
      mac                 AlgorithmIdentifier
      -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
}   -- or HMAC [RFC2104, RFC2202])

So the way this works is in two stages πŸ¦‹ The first stage takes shared secret information and turns it into a MAC key. The second stage MACs the public key in question with that MAC key, and that's what gives you the authenticated value. Iconic, honestly.

The setup for stage one assumes there's a shared secret that was passed along in a trusted way between the CA/RA and the end-entity. You append the salt value to the shared secret, then apply the one way function (owf) iterationCount times. The salted secret is the input to the first iteration, and every iteration after that takes the previous output as its input. What comes out at the end is a key K 🧚

For stage two, K and the public key go into HMAC as documented in [HMAC], and that produces the value for publicKeyMAC like this:

publicKeyMAC = Hash( K XOR opad, Hash( K XOR ipad, public key) )

ipad and opad are defined in [RFC2104].

The AlgorithmIdentifier for owf SHALL be SHA-1 {1 3 14 3 2 26}, and for mac SHALL be HMAC-SHA1 {1 3 6 1 5 5 8 1 2} πŸ’…


5. CertRequest syntax ✨

The CertRequest syntax is made up of a request identifier, a template of certificate content, and an optional sequence of control information πŸŽ€

CertRequest ::= SEQUENCE {
    certReqId     INTEGER,          -- ID for matching request and reply
    certTemplate  CertTemplate,  -- Selected fields of cert to be issued
    controls      Controls OPTIONAL }   -- Attributes affecting issuance

CertTemplate ::= SEQUENCE {
    version      [0] Version               OPTIONAL,
    serialNumber [1] INTEGER               OPTIONAL,
    signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
    issuer       [3] Name                  OPTIONAL,
    validity     [4] OptionalValidity      OPTIONAL,
    subject      [5] Name                  OPTIONAL,
    publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
    issuerUID    [7] UniqueIdentifier      OPTIONAL,
    subjectUID   [8] UniqueIdentifier      OPTIONAL,
    extensions   [9] Extensions            OPTIONAL }

  OptionalValidity ::= SEQUENCE {
      notBefore  [0] Time OPTIONAL,
      notAfter   [1] Time OPTIONAL } --at least one must be present

  Time ::= CHOICE {
      utcTime        UTCTime,
      generalTime    GeneralizedTime }

6. Controls Syntax 🌸

The generator of a CertRequest is allowed to include one or more control values that affect how the request gets processed πŸ’œ

Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue

These are the controls that are defined (it's recognized that this list may grow over time, so stay tuned πŸ‘€):

  • regToken
  • authenticator
  • pkiPublicationInfo
  • pkiArchiveOptions
  • oldCertID
  • protocolEncrKey

6.1. Registration Token Control πŸ”‘

A regToken control holds one-time info, either based on a secret value or on knowledge, that the CA is meant to use to check the subject's identity before it issues a certificate. When a certification request shows up with a value for regToken, the CA that receives it checks that info to confirm the identity the request claims ✨

The value for regToken can be generated by the CA and handed to the subscriber out of band, or it can already be available to both the CA and the subscriber. The security of any out-of-band exchange should be commensurate with the risk of the CA accepting an intercepted value from someone other than the intended subscriber. Be careful, bestie 😭

The regToken control would typically be used only for initializing an end entity into the PKI. The authenticator control (see Section 7.2) would typically be used for the initial request and for any requests after that 🫢

In some cases the value for regToken could be a text string or a numeric quantity, like a random number. If it's the latter, the value could be encoded either as a binary quantity or as a text string representation of that binary quantity. To make sure values are encoded the same way no matter what kind of quantity they are, the encoding of regToken SHALL be UTF8. πŸŽ€

6.2. Authenticator Control.

An authenticator control holds information that's used on an ongoing basis to set up a non-cryptographic check of identity when talking to the CA πŸ¦‹ Some examples are a mother's maiden name, the last four digits of a social security number, or other knowledge-based information shared with the subscriber's CA. It could also be a hash of that kind of information, or other information made for this purpose. The value for an authenticator control can be generated by the subscriber or by the CA.

In some cases the value for regToken could be a text string or a numeric quantity, like a random number. If it's the latter, the value could be encoded either as a binary quantity or as a text string representation of that binary quantity. To make sure values are encoded the same way no matter what kind of quantity they are, the encoding of authenticator SHALL be UTF8. πŸ’…

6.3. Publication Information Control πŸ“œ

The pkiPublicationInfo control lets subscribers decide what the CA does with publishing the certificate. It's defined by this syntax:

PKIPublicationInfo ::= SEQUENCE {
     action     INTEGER {
                  dontPublish (0),
                  pleasePublish (1) },
     pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }


       -- pubInfos MUST NOT be present if action is "dontPublish"
       -- (if action is "pleasePublish" and pubInfos is omitted,
       -- "dontCare" is assumed)

SinglePubInfo ::= SEQUENCE {
      pubMethod    INTEGER {
          dontCare    (0),
          x500        (1),
          web         (2),
          ldap        (3) },
      pubLocation  GeneralName OPTIONAL }

If you pick dontPublish, the requester is saying the PKI should not publish the certificate πŸ™ˆ (this might mean the requester plans to publish it themselves).

If you pick dontCare, or if the PKIPublicationInfo control is left out of the request, the requester is saying the PKI MAY publish the certificate using whatever means it likes 🌈

If the requester wants the certificate to show up in at least some places, but still wants the CA to be able to put it in other repositories, they set two values of SinglePubInfo for pubInfos: one with x500, web or ldap as the value, and one with dontCare πŸ“

The pubLocation field, if it's supplied, shows where the requester would like the certificate to be found. (Note that the CHOICE within GeneralName includes a URL and an IP address, for example 🧚)

6.4. Archive Options Control πŸ—„οΈ

The pkiArchiveOptions control lets subscribers supply the info needed to set up an archive of the private key that matches the public key in the certification request πŸ”₯ It's defined by this syntax:

PKIArchiveOptions ::= CHOICE {
      encryptedPrivKey     [0] EncryptedKey,
      -- the actual value of the private key
      keyGenParameters     [1] KeyGenParameters,
      -- parameters which allow the private key to be re-generated
      archiveRemGenPrivKey [2] BOOLEAN }
      -- set to TRUE if sender wishes receiver to archive the private
      -- key of a key pair which the receiver generates in response to
      -- this request; set to FALSE if no archival is desired.

EncryptedKey ::= CHOICE {
      encryptedValue        EncryptedValue,
      envelopedData     [0] EnvelopedData }
      -- The encrypted private key MUST be placed in the envelopedData
      -- encryptedContentInfo encryptedContent OCTET STRING.

EncryptedValue ::= SEQUENCE {
      intendedAlg   [0] AlgorithmIdentifier  OPTIONAL,
      -- the intended algorithm for which the value will be used
      symmAlg       [1] AlgorithmIdentifier  OPTIONAL,
      -- the symmetric algorithm used to encrypt the value
      encSymmKey    [2] BIT STRING           OPTIONAL,
      -- the (encrypted) symmetric key used to encrypt the value
      keyAlg        [3] AlgorithmIdentifier  OPTIONAL,
      -- algorithm used to encrypt the symmetric key
      valueHint     [4] OCTET STRING         OPTIONAL,
      -- a brief description or identifier of the encValue content
      -- (may be meaningful only to the sending entity, and used only
      -- if EncryptedValue might be re-examined by the sending entity
      -- in the future)
        encValue       BIT STRING }

KeyGenParameters ::= OCTET STRING

Another option, instead of sending the key itself, is to send info on how to regenerate the key using the KeyGenParameters choice. For example, many RSA implementations could send the first random numbers that were tested for primality 🎲 The actual syntax for this parameter may be defined in a subsequent version of this document or in another standard.

6.5. OldCert ID Control πŸͺͺ

If it's present, the OldCertID control specifies the certificate that the current certification request is updating. The syntax of its value is:

CertId ::= SEQUENCE {
      issuer           GeneralName,
      serialNumber     INTEGER
  }

6.6. Protocol Encryption Key Control πŸ—οΈ

If it's present, the protocolEncrKey control specifies a key that the CA will use to encrypt a response to CertReqMessages πŸ₯°

This control can be used when a CA has info it needs to send to the subscriber that has to be encrypted. That kind of info includes a private key the CA generated for the subscriber to use πŸ‘‘

The encoding of protocolEncrKey SHALL be SubjectPublicKeyInfo. πŸ’–


7. Object Identifiers 🏷️

The OID id-pkix has the value:

id-pkix  OBJECT IDENTIFIER  ::= { iso(1) identified-organization(3)
dod(6) internet(1) security(5) mechanisms(5) pkix(7) }

-- arc for Internet X.509 PKI protocols and their components
id-pkip  OBJECT IDENTIFIER :: { id-pkix pkip(5) }

-- Registration Controls in CRMF
id-regCtrl  OBJECT IDENTIFIER ::= { id-pkip regCtrl(1) }
id-regCtrl-regToken            OBJECT IDENTIFIER ::= { id-regCtrl 1 }
id-regCtrl-authenticator       OBJECT IDENTIFIER ::= { id-regCtrl 2 }
id-regCtrl-pkiPublicationInfo  OBJECT IDENTIFIER ::= { id-regCtrl 3 }
id-regCtrl-pkiArchiveOptions   OBJECT IDENTIFIER ::= { id-regCtrl 4 }
id-regCtrl-oldCertID           OBJECT IDENTIFIER ::= { id-regCtrl 5 }
id-regCtrl-protocolEncrKey     OBJECT IDENTIFIER ::= { id-regCtrl 6 }

-- Registration Info in CRMF
id-regInfo       OBJECT IDENTIFIER ::= { id-pkip id-regInfo(2) }
id-regInfo-asciiPairs    OBJECT IDENTIFIER ::= { id-regInfo 1 }
--with syntax OCTET STRING
id-regInfo-certReq       OBJECT IDENTIFIER ::= { id-regInfo 2 }
--with syntax CertRequest

8. Security Considerations 🚨

Heads up, this part is serious! The security of CRMF delivery depends on the security mechanisms of the protocol or process used to communicate with CAs. That protocol or process needs to ensure the integrity, data origin authenticity, and privacy of the message. Encryption of a CRMF is strongly recommended if it contains subscriber-sensitive information and if the CA has an encryption certificate that is known to the end entity πŸ”πŸ’œ

9. References ✨

Okay bestie, the reading list πŸ“š Just one to keep in your back pocket:

[HMAC] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, February 1997. πŸ”

10. Acknowledgments 🫢

The authors wanted to shoutout Barbara Fox, Warwick Ford, Russ Housley and John Pawling πŸ’– Their reviews and comments made this spec SO much clearer and more useful. Iconic behaviour from them πŸ‘‘

11. Authors' Addresses πŸŽ€

Michael Myers VeriSign, Inc. 1390 Shorebird Way Mountain View, CA 94019 EMail: mmyers@verisign.com

Carlisle Adams Entrust Technologies 750 Heron Road, Suite E08 Ottawa, Canada, K1V 1A7 EMail: cadams@entrust.com

Dave Solo Citicorp 666 Fifth Ave, 3rd Floor New York, Ny 10103 EMail: david.solo@citicorp.com

David Kemp National Security Agency Suite 6734 9800 Savage Road Fort Meade, MD 20755 EMail: dpkemp@missi.ncsc.mil

Appendix A. Constructing "dhMAC" 🧁

Okay this appendix is the recipe for the bit string "dhMAC" that lives inside the proof-of-possession POPOPrivKey structure. It's used for Diffie-Hellman certificate requests, and it's giving "prove you have the key without showing the key" energy πŸ¦‹

1. The entity generates a DH public/private key-pair.

The DH parameters used to calculate the public SHOULD be those specified in the CA's DH certificate. Wait, I'm not even going to have to fake that for you, it's literally just:

From CA's DH certificate:
   CApub = g^x mod p   (where g and p are the established DH
                        parameters and x is the CA's private
                        DH component)
For entity E:
   DH private value = y
   Epub = DH public value = g^y mod p

2. The MACing process will then consist of the following steps.

a) The value of the certReq field is DER encoded, yielding a binary string. This will be the 'text' referred to in [HMAC], the data to which HMAC-SHA1 is applied. πŸ“¦

b) A shared DH secret is computed, as follows:

shared secret = Kec = g^xy mod p

This is done by the entity E as CApub^y and by the CA as Epub^x, where CApub is retrieved from the CA's DH certificate and Epub is retrieved from the actual certification request. 🀝

c) A key K is derived from the shared secret Kec and the subject and issuer names in the CA's certificate as follows:

K = SHA1(DER-encoded-subjectName | Kec | DER-encoded-issuerName)

where "|" means concatenation. If subjectName in the CA certificate is an empty SEQUENCE then DER-encoded-subjectAltName should be used instead; similarly, if issuerName is an empty SEQUENCE then DER-encoded-issuerAltName should be used instead. 🧠

d) Compute HMAC-SHA1 over the data 'text' as per [RFC2104] as:

SHA1(K XOR opad, SHA1(K XOR ipad, text))

where,

opad (outer pad) = the byte 0x36 repeated 64 times

and

ipad (inner pad) = the byte 0x5C repeated 64 times.

Namely:

  • (1) Append zeros to the end of K to create a 64 byte string (e.g., if K is of length 16 bytes it will be appended with 48 zero bytes 0x00).
  • (2) XOR (bitwise exclusive-OR) the 64 byte string computed in step (1) with ipad.
  • (3) Append the data stream 'text' to the 64 byte string resulting from step (2).
  • (4) Apply SHA1 to the stream generated in step (3).
  • (5) XOR (bitwise exclusive-OR) the 64 byte string computed in step (1) with opad.
  • (6) Append the SHA1 result from step (4) to the 64 byte string resulting from step (5).
  • (7) Apply SHA1 to the stream generated in step (6) and output the result.

Sample code is also provided in [RFC2104, RFC2202]. πŸ’»

e) The output of (d) is encoded as a BIT STRING (the value "dhMAC").

3. The proof-of-possession process requires the CA to carry out steps (a) through (d) and then simply compare the result of step (d) with what it received as the "dhMAC" value. If they match then the following can be concluded.

1) The Entity possesses the private key corresponding to the public key in the certification request (because it needed the private key to calculate the shared secret). πŸ”‘

2) Only the intended CA can actually verify the request (because the CA requires its own private key to compute the same shared secret). This helps to protect from rogue CAs. πŸ›‘οΈ

This is the bit that keeps the bad CAs out, so don't skip it πŸ’€

References

[RFC2104] Krawczyk, H., Bellare, M. and R. Canetti, "HMAC: Keyed Hashing for Message Authentication", RFC 2104, February 1997.

[RFC2202] Cheng, P. and R. Glenn, "Test Cases for HMAC-MD5 and HMAC-SHA-1", RFC 2202, September 1997.

Acknowledgements

The details of this Appendix were provided by Hemma Prafullchandra. 🌸

Appendix B. Use of RegInfo for Name-Value Pairs πŸ“

The "value" field of the id-regInfo-utf8Pairs OCTET STRING (with "tag" field equal to 12 and appropriate "length" field) will contain a series of UTF8 name/value pairs. Basically, a little bag of key-value gossip πŸ’…

This appendix lists some common examples of such pairs so that independent implementations can actually understand each other. It's recognized that this list is not exhaustive and will grow with time and implementation experience, so no stress if your implementation has its own vibes ✨

B.1. Example Name/Value Pairs

When regInfo is used to convey one or more name-value pairs (via id-regInfo-utf8Pairs), the first and subsequent pairs SHALL be structured as follows:

[name?value][%name?value]*%

This string is then encoded into an OCTET STRING and placed into the regInfo SEQUENCE.

Reserved characters are encoded using the %xx mechanism of [RFC1738], unless they are used for their reserved purposes.

The following table defines a recommended set of named elements. The value in the column "Name Value" is the exact text string that will appear in the regInfo.

Name Value
----------
version            -- version of this variation of regInfo use
corp_company       -- company affiliation of subscriber
org_unit           -- organizational unit
mail_firstName     -- personal name component
mail_middleName    -- personal name component
mail_lastName      -- personal name component
mail_email         -- subscriber's email address
jobTitle           -- job title of subscriber
employeeID         -- employee identification number or string

mailStop           -- mail stop
issuerName         -- name of CA
subjectName        -- name of Subject
validity           -- validity interval

For example:

version?1%corp_company?Acme, Inc.%org_unit?Engineering%
mail_firstName?John%mail_lastName?Smith%jobTitle?Team Leader%
mail_email?john@acme.com%

B.1.1. IssuerName, SubjectName and Validity Value Encoding

When they appear in id-regInfo-utf8Pairs syntax as named elements, the encoding of values for issuerName, subjectName and validity SHALL use the following syntax. The characters [] indicate an optional field, ::= and | have their usual BNF meanings, and all other symbols (except spaces which are insignificant) outside non-terminal names are terminals. Alphabetics are case-sensitive.

issuerName  ::= <names>
subjectName ::= <names>
<names>     ::= <name> | <names>:<name>

<validity>  ::= validity ? [<notbefore>]-[<notafter>]
<notbefore> ::= <time>
<notafter>  ::= <time>

Where <time> is UTC time in the form YYYYMMDD[HH[MM[SS]]]. HH, MM, and SS default to 00 and are omitted if at the and of value 00.

Example validity encoding:

validity?-19991231%

is a validity interval with no value for notBefore and a value of December 31, 1999 for notAfter.

Each name comprises a single character name form identifier followed by a name value of one or UTF8 characters. Within a name value, when it is necessary to disambiguate a character which has formatting significance at an outer level, the escape sequence %xx SHALL be used, where xx represents the hex value for the encoding concerned. The percent symbol is represented by %%.

<name> ::= X<xname>|O<oname>|E<ename>|D<dname>|U<uname>|I<iname>

Name forms and value formats are as follows:

X.500 directory name form (identifier "X"):

<xname> ::= <rdns>
<rdns>  ::= <rdn> | <rdns> , <rdn>
<rdn>   ::= <avas>
<avas>  ::= <ava> | <avas> + <ava>
<ava>   ::= <attyp> = <avalue>
<attyp> ::= OID.<oid> | <stdat>

Standard attribute type <stdat> is an alphabetic attribute type identifier from the following set:

C      (country)
L      (locality)
ST     (state or province)
O      (organization)
OU     (organizational unit)
CN     (common name)
STREET (street address)
E      (E-mail address)

<avalue> is a name component in the form of a UTF8 character string of 1 to 64 characters, with the restriction that in the IA5 subset of UTF8 only the characters of ASN.1 PrintableString may be used.

Other name form (identifier "O"):

<oname> ::= <oid> , <utf8string>

E-mail address (rfc822name) name form (identifier "E"):

<ename> ::= <ia5string>

DNS name form (identifier "D"):

<dname> ::= <ia5string>

URI name form (identifier "U"):

<uname> ::= <ia5string>

IP address (identifier "I"):

<iname> ::= <oid>

For example:

issuerName?XOU=Our CA,O=Acme,C=US%
subjectName?XCN=John Smith, O=Acme, C=US, E=john@acme.com%

References

[RFC1738] Berners-Lee, T., Masinter, L. and M. McCahill, "Uniform Resource Locators (URL)", RFC 1738, December 1994. πŸ”—

Appendix C. ASN.1 Structures and OIDs 🧩

Last stop for this part: the ASN.1 module. Here's where all the structures and OIDs live, so it's giving very official but also very organized πŸ’œ

PKIXCRMF {iso(1) identified-organization(3) dod(6) internet(1)
   security(5) mechanisms(5) pkix(7) id-mod(0) id-mod-crmf(5)}

CRMF DEFINITIONS IMPLICIT TAGS ::=
BEGIN

IMPORTS
     -- Directory Authentication Framework (X.509)
        Version, AlgorithmIdentifier, Name, Time,
        SubjectPublicKeyInfo, Extensions, UniqueIdentifier
           FROM PKIX1Explicit88 {iso(1) identified-organization(3) dod(6)
               internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
               id-pkix1-explicit-88(1)}

     -- Certificate Extensions (X.509)
        GeneralName
           FROM PKIX1Implicit88 {iso(1) identified-organization(3) dod(6)
                  internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
                  id-pkix1-implicit-88(2)}

     -- Cryptographic Message Syntax
        EnvelopedData
           FROM CryptographicMessageSyntax { iso(1) member-body(2)
                us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16)
                modules(0) cms(1) };

CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg

CertReqMsg ::= SEQUENCE {
    certReq   CertRequest,
    pop       ProofOfPossession  OPTIONAL,
    -- content depends upon key type
    regInfo   SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue OPTIONAL }

CertRequest ::= SEQUENCE {
    certReqId     INTEGER,          -- ID for matching request and reply
    certTemplate  CertTemplate,  -- Selected fields of cert to be issued
    controls      Controls OPTIONAL }   -- Attributes affecting issuance

CertTemplate ::= SEQUENCE {
    version      [0] Version               OPTIONAL,
    serialNumber [1] INTEGER               OPTIONAL,
    signingAlg   [2] AlgorithmIdentifier   OPTIONAL,
    issuer       [3] Name                  OPTIONAL,
    validity     [4] OptionalValidity      OPTIONAL,
    subject      [5] Name                  OPTIONAL,
    publicKey    [6] SubjectPublicKeyInfo  OPTIONAL,
    issuerUID    [7] UniqueIdentifier      OPTIONAL,
    subjectUID   [8] UniqueIdentifier      OPTIONAL,
    extensions   [9] Extensions            OPTIONAL }

okay so the ASN.1 module keeps going, and it's giving proof-of-possession πŸ”βœ¨

OptionalValidity ::= SEQUENCE {
    notBefore  [0] Time OPTIONAL,
    notAfter   [1] Time OPTIONAL } --at least one MUST be present

Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue

AttributeTypeAndValue ::= SEQUENCE {
    type         OBJECT IDENTIFIER,
    value        ANY DEFINED BY type }

ProofOfPossession ::= CHOICE {
    raVerified        [0] NULL,
    -- used if the RA has already verified that the requester is in
    -- possession of the private key
    signature         [1] POPOSigningKey,
    keyEncipherment   [2] POPOPrivKey,
    keyAgreement      [3] POPOPrivKey }

POPOSigningKey ::= SEQUENCE {
    poposkInput           [0] POPOSigningKeyInput OPTIONAL,
    algorithmIdentifier   AlgorithmIdentifier,
    signature             BIT STRING }
    -- The signature (using "algorithmIdentifier") is on the
    -- DER-encoded value of poposkInput.  NOTE: If the CertReqMsg
    -- certReq CertTemplate contains the subject and publicKey values,
    -- then poposkInput MUST be omitted and the signature MUST be
    -- computed on the DER-encoded value of CertReqMsg certReq.  If
    -- the CertReqMsg certReq CertTemplate does not contain the public
    -- key and subject values, then poposkInput MUST be present and
    -- MUST be signed.  This strategy ensures that the public key is
    -- not present in both the poposkInput and CertReqMsg certReq
    -- CertTemplate fields.

POPOSigningKeyInput ::= SEQUENCE {
    authInfo            CHOICE {
        sender              [0] GeneralName,
        -- used only if an authenticated identity has been
        -- established for the sender (e.g., a DN from a
        -- previously-issued and currently-valid certificate
        publicKeyMAC        PKMACValue },
        -- used if no authenticated GeneralName currently exists for
        -- the sender; publicKeyMAC contains a password-based MAC
        -- on the DER-encoded value of publicKey

    publicKey           SubjectPublicKeyInfo }  -- from CertTemplate

PKMACValue ::= SEQUENCE {
   algId  AlgorithmIdentifier,
   -- algorithm value shall be PasswordBasedMac {1 2 840 113533 7 66 13}
   -- parameter value is PBMParameter
   value  BIT STRING }

PBMParameter ::= SEQUENCE {
      salt                OCTET STRING,
      owf                 AlgorithmIdentifier,
      -- AlgId for a One-Way Function (SHA-1 recommended)
      iterationCount      INTEGER,
      -- number of times the OWF is applied
      mac                 AlgorithmIdentifier
      -- the MAC AlgId (e.g., DES-MAC, Triple-DES-MAC [PKCS11],
}   -- or HMAC [RFC2104, RFC2202])

POPOPrivKey ::= CHOICE {
    thisMessage       [0] BIT STRING,
    -- posession is proven in this message (which contains the private
    -- key itself (encrypted for the CA))
    subsequentMessage [1] SubsequentMessage,
    -- possession will be proven in a subsequent message
    dhMAC             [2] BIT STRING }
    -- for keyAgreement (only), possession is proven in this message
    -- (which contains a MAC (over the DER-encoded value of the
    -- certReq parameter in CertReqMsg, which MUST include both subject
    -- and publicKey) based on a key derived from the end entity's
    -- private DH key and the CA's public DH key);
    -- the dhMAC value MUST be calculated as per the directions given
    -- in Appendix A.

SubsequentMessage ::= INTEGER {
    encrCert (0),
    -- requests that resulting certificate be encrypted for the
    -- end entity (following which, POP will be proven in a
    -- confirmation message)
    challengeResp (1) }
    -- requests that CA engage in challenge-response exchange with
    -- end entity in order to prove private key possession

-- Object identifier assignments --

id-pkix  OBJECT IDENTIFIER  ::= { iso(1) identified-organization(3)
dod(6) internet(1) security(5) mechanisms(5) 7 }

-- arc for Internet X.509 PKI protocols and their components
id-pkip  OBJECT IDENTIFIER ::= { id-pkix 5 }

-- Registration Controls in CRMF
id-regCtrl OBJECT IDENTIFIER ::= { id-pkip 1 }

-- The following definition may be uncommented for use with
-- ASN.1 compilers which do not understand UTF8String.

-- UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING

id-regCtrl-regToken OBJECT IDENTIFIER ::= { id-regCtrl 1 }
--with syntax:
RegToken ::= UTF8String

id-regCtrl-authenticator OBJECT IDENTIFIER ::= { id-regCtrl 2 }
--with syntax:
Authenticator ::= UTF8String

id-regCtrl-pkiPublicationInfo OBJECT IDENTIFIER ::= { id-regCtrl 3 }
--with syntax:

PKIPublicationInfo ::= SEQUENCE {
   action     INTEGER {
                dontPublish (0),
                pleasePublish (1) },
   pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
     -- pubInfos MUST NOT be present if action is "dontPublish"
     -- (if action is "pleasePublish" and pubInfos is omitted,
     -- "dontCare" is assumed)

SinglePubInfo ::= SEQUENCE {
    pubMethod    INTEGER {
        dontCare    (0),
        x500        (1),
        web         (2),
        ldap        (3) },
    pubLocation  GeneralName OPTIONAL }

id-regCtrl-pkiArchiveOptions     OBJECT IDENTIFIER ::= { id-regCtrl 4 }
--with syntax:
PKIArchiveOptions ::= CHOICE {
    encryptedPrivKey     [0] EncryptedKey,
    -- the actual value of the private key
    keyGenParameters     [1] KeyGenParameters,
    -- parameters which allow the private key to be re-generated
    archiveRemGenPrivKey [2] BOOLEAN }
    -- set to TRUE if sender wishes receiver to archive the private
    -- key of a key pair which the receiver generates in response to
    -- this request; set to FALSE if no archival is desired.

EncryptedKey ::= CHOICE {
    encryptedValue        EncryptedValue,
    envelopedData     [0] EnvelopedData }
    -- The encrypted private key MUST be placed in the envelopedData
    -- encryptedContentInfo encryptedContent OCTET STRING.


EncryptedValue ::= SEQUENCE {
    intendedAlg   [0] AlgorithmIdentifier  OPTIONAL,
    -- the intended algorithm for which the value will be used
    symmAlg       [1] AlgorithmIdentifier  OPTIONAL,
    -- the symmetric algorithm used to encrypt the value
    encSymmKey    [2] BIT STRING           OPTIONAL,
    -- the (encrypted) symmetric key used to encrypt the value
    keyAlg        [3] AlgorithmIdentifier  OPTIONAL,
    -- algorithm used to encrypt the symmetric key
    valueHint     [4] OCTET STRING         OPTIONAL,
    -- a brief description or identifier of the encValue content
    -- (may be meaningful only to the sending entity, and used only
    -- if EncryptedValue might be re-examined by the sending entity
    -- in the future)
    encValue       BIT STRING }
    -- the encrypted value itself

KeyGenParameters ::= OCTET STRING

id-regCtrl-oldCertID          OBJECT IDENTIFIER ::= { id-regCtrl 5 }
--with syntax:
OldCertId ::= CertId

CertId ::= SEQUENCE {
    issuer           GeneralName,
    serialNumber     INTEGER }

id-regCtrl-protocolEncrKey    OBJECT IDENTIFIER ::= { id-regCtrl 6 }
--with syntax:
ProtocolEncrKey ::= SubjectPublicKeyInfo

-- Registration Info in CRMF
id-regInfo OBJECT IDENTIFIER ::= { id-pkip 2 }

id-regInfo-utf8Pairs    OBJECT IDENTIFIER ::= { id-regInfo 1 }
--with syntax
UTF8Pairs ::= UTF8String

id-regInfo-certReq       OBJECT IDENTIFIER ::= { id-regInfo 2 }
--with syntax
CertReq ::= CertRequest

END

Okay, the legal bit, and it's still important, bestie πŸ’… Copyright is held by The Internet Society (1999), and all rights are reserved πŸ¦‹

This document and translations of it can be copied and handed out to others. Derivative works that comment on or explain it, or help with implementing it, can be made, copied, published and distributed, in whole or in part, with no restrictions of any kind, as long as the copyright notice and this paragraph are included on all of those copies and derivative works. The document itself can't be modified in any way, like removing the copyright notice or the references to the Internet Society or other Internet organizations. The exception is when it's needed for developing Internet standards, in which case the copyright procedures in the Internet Standards process have to be followed. Translating it into languages other than English is also allowed 🌈

The limited permissions above are perpetual, and the Internet Society or its successors or assigns will never revoke them πŸ’œ

This document and the information in it is provided "AS IS", and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 😭🫢

πŸ“¦ where this page comes from