RFC 9654
Online Certificate Status Protocol (OCSP) Nonce Extension
Online Certificate Status Protocol (OCSP) Nonce Extension ๐โจ
Okay bestie, this one is an IETF standards track doc, so it's official ๐ It's RFC 9654, written by H. Sharma, Ed. from Netskope Inc and dated August 2024. It's Standards Track, ISSN 2070-1721, and it obsoletes RFC 8954 and updates RFC 6960. Basically, it's a glow-up of the Nonce extension for OCSP ๐ฆ
Abstract
Okay so, OCSP is how you check whether a certificate is still valid ๐ The Nonce extension is the part that cryptographically binds an OCSP response to the specific OCSP request it answers. Like, it's the matching bracelet that proves the reply is for your question ๐
Here's the tea: RFC 8954 put size limits on that Nonce, and some environments use crypto algorithms that make Nonces longer than 32 octets ๐ญ So this doc fixes that, and it also rewrites the "Nonce" section of RFC 6960 so the encoding format and values are way clearer to implement. It obsoletes RFC 8954 (and brings updated ASN.1 modules for OCSP) and updates RFC 6960. Iconic ๐
Status of This Memo
This is an Internet Standards Track document. ๐ธ
It's a product of the Internet Engineering Task Force (IETF), so it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check Section 2 of RFC 7841.
For the current status, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc9654 ๐ง
Copyright Notice
Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved. ๐
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the date of publication. Please read these carefully, because they spell out your rights and restrictions for this document. Code Components pulled out of this document must include the Revised BSD License text described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Revised BSD License. โ ๏ธ
Table of Contents
1. Introduction
1.1. Requirements Language
2. OCSP Extensions
2.1. Nonce Extension
3. Security Considerations
3.1. Replay Attack
4. IANA Considerations
5. References
5.1. Normative References
5.2. Informative References
Appendix A. ASN.1 Modules
A.1. OCSP in ASN.1 - 1998 Syntax
A.2. OCSP in ASN.1 - 2008 Syntax
Acknowledgements
Author's Address
1. Introduction โจ
Okay so the Nonce extension was first defined in Section 4.4.1 of [RFC6960] ๐ The Nonce is what cryptographically binds an OCSP request and response together. It's the thing that guarantees the freshness of a response and helps avoid replay attacks. [RFC8954] later updated this extension and limited the maximum Nonce length to 32 octets.
Now here's the glow-up: to support crypto algorithms that generate a Nonce longer than 32 octets, this document raises the maximum allowed Nonce size to 128 octets ๐ฆ It also recommends that the OCSP requester and responder use a Nonce with a minimum length of 32 octets. Very responsible of them ๐ซถ
1.1. Requirements Language
Okay, this part is the rulebook for the capitalized words ๐ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here. So if you see them in caps, they're doing a job. If they're lowercase, they're just vibes ๐
2. OCSP Extensions ๐
The message formats for OCSP requests and responses are defined in [RFC6960], and the Nonce extension was updated in [RFC8954]. [RFC6960] also defines the standard extensions for OCSP messages, based on the extension model used in X.509 version 3 certificates (see [RFC5280]). [RFC8954] replaces Section 4.4.1 of [RFC6960] to limit the minimum and maximum length of the Nonce value. This document extends the maximum allowed nonce length to 128 octets, and it doesn't change the specifications of any of the other extensions defined in [RFC6960]. Just the Nonce, bestie, nothing else gets touched ๐
2.1. Nonce Extension
Okay, the main event ๐ The Nonce cryptographically binds a request and a response to prevent replay attacks. In requests it goes in the requestExtensions, and in responses it goes in the responseExtensions. In both, the Nonce is identified by the object identifier id-pkix-ocsp-nonce, and the extnValue is the encoded value of the Nonce. If the Nonce extension is present, then the length of the Nonce MUST be at least 1 octet and can be up to 128 octets. Implementations compliant with [RFC8954] won't be able to process nonces made under this new spec if they're bigger than the 32-octet limit in [RFC8954], so that's a real heads-up ๐
An OCSP requester that implements the extension in this document MUST use a minimum length of 32 octets for the Nonce in the Nonce extension. No shortcuts, periodt โจ
An OCSP responder that supports the Nonce extension MUST accept Nonce lengths of at least 16 octets and up to and including 32 octets. A responder MAY choose to respond without the Nonce extension for requests where the Nonce length is between 1 octet and 15 octets, or between 33 octets and 128 octets. So responders get a little choice here ๐ง
Responders that implement the extension in this document MUST reject any OCSP request that has a Nonce with a length of either 0 octets or greater than 128 octets. They reject it with the malformedRequest OCSPResponseStatus, as described in Section 4.2.1 of [RFC6960]. Bye bye, bad Nonces ๐
The value of the Nonce MUST be generated using a cryptographically strong pseudorandom number generator (see [RFC4086]). The minimum Nonce length of 1 octet is defined so that it's backward compatible with older OCSP requesters that follow [RFC6960] ๐ธ
Here's the ASN.1 stuff for the object identifiers and the Nonce type:
id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
Nonce ::= OCTET STRING(SIZE(1..128))
And here's an example of an encoded OCSP Nonce extension with a 32-octet Nonce, shown in hexadecimal format. It's giving hex, it's giving structure ๐ค
30 2f 06 09 2b 06 01 05 05 07 30 01 02 04 22 04
20 dd 49 d4 07 2c 44 9d a1 c3 17 bd 1c 1b df fe
db e1 50 31 2e c4 cd 0a dd 18 e5 bd 6f 84 bf 14
c8
Here's the decoded version of that example. Offset, Length, and Object Identifier are in decimal, so it's easy to follow along ๐งฎ
Offset Length
0 47 : SEQUENCE {
2 9 : OBJECT IDENTIFIER ocspNonce
: (1 3 6 1 5 5 7 48 1 2)
13 34 : OCTET STRING, encapsulates {
15 32 : OCTET STRING
: DD 49 D4 07 2C 44 9D A1 C3 17 BD 1C 1B DF FE DB
: E1 50 31 2E C4 CD 0A DD 18 E5 BD 6F 84 BF 14 C8
: }
: }
Okay bestie, this is the ASN.1 module where all the OCSP structures live ๐ It's giving very precise, and every field matters ๐ง
A.1. OCSP in ASN.1 - 1998 Syntax โจ
<CODE BEGINS>
OCSP-2024-88
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-ocsp-2024-88(111) }
DEFINITIONS EXPLICIT TAGS ::=
BEGIN
IMPORTS
AuthorityInfoAccessSyntax, CRLReason, GeneralName
FROM PKIX1Implicit88 -- From [RFC5280]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-pkix1-implicit(19) }
Name, CertificateSerialNumber, Extensions,
id-kp, id-ad-ocsp, Certificate, AlgorithmIdentifier
FROM PKIX1Explicit88 -- From [RFC5280]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-pkix1-explicit(18) } ;
OCSPRequest ::= SEQUENCE {
tbsRequest TBSRequest,
optionalSignature [0] EXPLICIT Signature OPTIONAL }
TBSRequest ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
requestorName [1] EXPLICIT GeneralName OPTIONAL,
requestList SEQUENCE OF Request,
requestExtensions [2] EXPLICIT Extensions OPTIONAL }
Signature ::= SEQUENCE {
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF
Certificate OPTIONAL }
Version ::= INTEGER { v1(0) }
Nonce ::= OCTET STRING (SIZE(1..128))
Request ::= SEQUENCE {
reqCert CertID,
singleRequestExtensions [0] EXPLICIT
Extensions OPTIONAL }
CertID ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier,
issuerNameHash OCTET STRING, -- Hash of issuer's DN
issuerKeyHash OCTET STRING, -- Hash of issuer's public key
serialNumber CertificateSerialNumber }
OCSPResponse ::= SEQUENCE {
responseStatus OCSPResponseStatus,
responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
OCSPResponseStatus ::= ENUMERATED {
successful (0), -- Response has valid confirmations
malformedRequest (1), -- Illegal confirmation request
internalError (2), -- Internal error in issuer
tryLater (3), -- Try again later
-- (4) is not used
sigRequired (5), -- Must sign the request
unauthorized (6) -- Request unauthorized
}
ResponseBytes ::= SEQUENCE {
responseType OBJECT IDENTIFIER,
response OCTET STRING }
BasicOCSPResponse ::= SEQUENCE {
tbsResponseData ResponseData,
signatureAlgorithm AlgorithmIdentifier,
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF
Certificate OPTIONAL }
ResponseData ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
responderID ResponderID,
producedAt GeneralizedTime,
-- The format for GeneralizedTime is
-- as specified in Section 4.1.2.5.2
-- [RFC5280]
responses SEQUENCE OF SingleResponse,
responseExtensions [1] EXPLICIT Extensions OPTIONAL }
ResponderID ::= CHOICE {
byName [1] Name,
byKey [2] KeyHash }
KeyHash ::= OCTET STRING
-- SHA-1 hash of responder's public key (i.e., the
-- SHA-1 hash of the value of the BIT STRING
-- subjectPublicKey [excluding the tag, length, and
-- number of unused bits] in the responder's
-- certificate)
SingleResponse ::= SEQUENCE {
certID CertID,
certStatus CertStatus,
thisUpdate GeneralizedTime,
nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
singleExtensions [1] EXPLICIT Extensions OPTIONAL }
CertStatus ::= CHOICE {
good [0] IMPLICIT NULL,
revoked [1] IMPLICIT RevokedInfo,
unknown [2] IMPLICIT UnknownInfo }
RevokedInfo ::= SEQUENCE {
revocationTime GeneralizedTime,
revocationReason [0] EXPLICIT CRLReason OPTIONAL }
UnknownInfo ::= NULL
ArchiveCutoff ::= GeneralizedTime
AcceptableResponses ::= SEQUENCE OF OBJECT IDENTIFIER
ServiceLocator ::= SEQUENCE {
issuer Name,
locator AuthorityInfoAccessSyntax }
CrlID ::= SEQUENCE {
crlUrl [0] EXPLICIT IA5String OPTIONAL,
crlNum [1] EXPLICIT INTEGER OPTIONAL,
crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }
PreferredSignatureAlgorithms ::= SEQUENCE OF
PreferredSignatureAlgorithm
PreferredSignatureAlgorithm ::= SEQUENCE {
sigIdentifier AlgorithmIdentifier,
certIdentifier AlgorithmIdentifier OPTIONAL }
-- Object Identifiers
id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 }
id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 }
id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 }
id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 }
id-pkix-ocsp-pref-sig-algs OBJECT IDENTIFIER ::= { id-pkix-ocsp 8 }
id-pkix-ocsp-extended-revoke OBJECT IDENTIFIER ::= { id-pkix-ocsp 9 }
END
<CODE ENDS>
Next up is the rest of the appendix, so stay tuned ๐ซถ
A.2. OCSP in ASN.1 - 2008 Syntax โจ
Okay bestie, here's the 2008-syntax module, the one with all the ASN.1 drama ๐
<CODE BEGINS>
OCSP-2024-08
{ iso(1) identified-organization(3) dod(6) internet(1)
security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-ocsp-2024-08(112) }
DEFINITIONS EXPLICIT TAGS ::=
BEGIN
IMPORTS
Extensions{}, EXTENSION
FROM PKIX-CommonTypes-2009 -- From [RFC5912]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-mod-pkixCommon-02(57) }
AlgorithmIdentifier{}, DIGEST-ALGORITHM,
SIGNATURE-ALGORITHM, PUBLIC-KEY
FROM AlgorithmInformation-2009 -- From [RFC5912]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-mod-algorithmInformation-02(58) }
AuthorityInfoAccessSyntax, GeneralName,
CrlEntryExtensions, CRLReason
FROM PKIX1Implicit-2009 -- From [RFC5912]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-mod-pkix1-implicit-02(59) }
Name, Certificate, CertificateSerialNumber,
id-kp, id-ad-ocsp
FROM PKIX1Explicit-2009 -- From [RFC5912]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-mod-pkix1-explicit-02(51) }
sa-dsaWithSHA1, sa-rsaWithMD2,
sa-rsaWithMD5, sa-rsaWithSHA1
FROM PKIXAlgs-2009 -- From [RFC5912]
{ iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7)
id-mod(0) id-mod-pkix1-algorithms2008-02(56) } ;
OCSPRequest ::= SEQUENCE {
tbsRequest TBSRequest,
optionalSignature [0] EXPLICIT Signature OPTIONAL }
TBSRequest ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
requestorName [1] EXPLICIT GeneralName OPTIONAL,
requestList SEQUENCE OF Request,
requestExtensions [2] EXPLICIT Extensions
{{ re-ocsp-nonce | re-ocsp-response |
re-ocsp-preferred-signature-algorithms,
... }} OPTIONAL }
Signature ::= SEQUENCE {
signatureAlgorithm AlgorithmIdentifier
{ SIGNATURE-ALGORITHM, {...}},
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF
Certificate OPTIONAL }
Version ::= INTEGER { v1(0) }
Nonce ::= OCTET STRING (SIZE(1..128))
Request ::= SEQUENCE {
reqCert CertID,
singleRequestExtensions [0] EXPLICIT Extensions
{{ re-ocsp-service-locator,
... }} OPTIONAL }
CertID ::= SEQUENCE {
hashAlgorithm AlgorithmIdentifier
{ DIGEST-ALGORITHM, {...}},
issuerNameHash OCTET STRING, -- Hash of issuer's DN
issuerKeyHash OCTET STRING, -- Hash of issuer's public key
serialNumber CertificateSerialNumber }
OCSPResponse ::= SEQUENCE {
responseStatus OCSPResponseStatus,
responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
OCSPResponseStatus ::= ENUMERATED {
successful (0), -- Response has valid confirmations
malformedRequest (1), -- Illegal confirmation request
internalError (2), -- Internal error in issuer
tryLater (3), -- Try again later
-- (4) is not used
sigRequired (5), -- Must sign the request
unauthorized (6) -- Request unauthorized
}
RESPONSE ::= TYPE-IDENTIFIER
ResponseSet RESPONSE ::= { basicResponse, ... }
ResponseBytes ::= SEQUENCE {
responseType RESPONSE.&id ({ResponseSet}),
response OCTET STRING (CONTAINING RESPONSE.
&Type({ResponseSet}{@responseType}))}
basicResponse RESPONSE ::=
{ BasicOCSPResponse IDENTIFIED BY id-pkix-ocsp-basic }
BasicOCSPResponse ::= SEQUENCE {
tbsResponseData ResponseData,
signatureAlgorithm AlgorithmIdentifier
{ SIGNATURE-ALGORITHM,
{ sa-dsaWithSHA1 |
sa-rsaWithSHA1 |
sa-rsaWithMD5 |
sa-rsaWithMD2,
... }},
signature BIT STRING,
certs [0] EXPLICIT SEQUENCE OF
Certificate OPTIONAL }
ResponseData ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
responderID ResponderID,
producedAt GeneralizedTime,
responses SEQUENCE OF SingleResponse,
responseExtensions [1] EXPLICIT Extensions
{{ re-ocsp-nonce |
re-ocsp-extended-revoke,
... }} OPTIONAL }
ResponderID ::= CHOICE {
byName [1] Name,
byKey [2] KeyHash }
KeyHash ::= OCTET STRING
-- SHA-1 hash of responder's public key
-- (excluding the tag and length and number
-- of unused bits)
SingleResponse ::= SEQUENCE {
certID CertID,
certStatus CertStatus,
thisUpdate GeneralizedTime,
nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
singleExtensions [1] EXPLICIT Extensions
{{ re-ocsp-crl |
re-ocsp-archive-cutoff |
CrlEntryExtensions,
... }} OPTIONAL }
CertStatus ::= CHOICE {
good [0] IMPLICIT NULL,
revoked [1] IMPLICIT RevokedInfo,
unknown [2] IMPLICIT UnknownInfo }
RevokedInfo ::= SEQUENCE {
revocationTime GeneralizedTime,
revocationReason [0] EXPLICIT CRLReason OPTIONAL }
UnknownInfo ::= NULL
ArchiveCutoff ::= GeneralizedTime
AcceptableResponses ::= SEQUENCE OF RESPONSE.&id({ResponseSet})
ServiceLocator ::= SEQUENCE {
issuer Name,
locator AuthorityInfoAccessSyntax }
CrlID ::= SEQUENCE {
crlUrl [0] EXPLICIT IA5String OPTIONAL,
crlNum [1] EXPLICIT INTEGER OPTIONAL,
crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }
PreferredSignatureAlgorithms ::= SEQUENCE OF
PreferredSignatureAlgorithm
PreferredSignatureAlgorithm ::= SEQUENCE {
sigIdentifier AlgorithmIdentifier
{ SIGNATURE-ALGORITHM, {...} },
certIdentifier AlgorithmIdentifier {PUBLIC-KEY, {...}}
OPTIONAL }
-- Certificate Extensions
ext-ocsp-nocheck EXTENSION ::= {
SYNTAX NULL IDENTIFIED BY id-pkix-ocsp-nocheck }
-- Request Extensions
re-ocsp-nonce EXTENSION ::= {
SYNTAX Nonce IDENTIFIED BY id-pkix-ocsp-nonce }
re-ocsp-response EXTENSION ::= {
SYNTAX AcceptableResponses IDENTIFIED BY
id-pkix-ocsp-response }
re-ocsp-service-locator EXTENSION ::= {
SYNTAX ServiceLocator IDENTIFIED BY
id-pkix-ocsp-service-locator }
re-ocsp-preferred-signature-algorithms EXTENSION ::= {
SYNTAX PreferredSignatureAlgorithms IDENTIFIED BY
id-pkix-ocsp-pref-sig-algs }
-- Response Extensions
re-ocsp-crl EXTENSION ::= {
SYNTAX CrlID IDENTIFIED BY id-pkix-ocsp-crl }
re-ocsp-archive-cutoff EXTENSION ::= {
SYNTAX ArchiveCutoff IDENTIFIED BY
id-pkix-ocsp-archive-cutoff }
re-ocsp-extended-revoke EXTENSION ::= {
SYNTAX NULL IDENTIFIED BY id-pkix-ocsp-extended-revoke }
-- Object Identifiers
id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
id-pkix-ocsp OBJECT IDENTIFIER ::= id-ad-ocsp
id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }
id-pkix-ocsp-crl OBJECT IDENTIFIER ::= { id-pkix-ocsp 3 }
id-pkix-ocsp-response OBJECT IDENTIFIER ::= { id-pkix-ocsp 4 }
id-pkix-ocsp-nocheck OBJECT IDENTIFIER ::= { id-pkix-ocsp 5 }
id-pkix-ocsp-archive-cutoff OBJECT IDENTIFIER ::= { id-pkix-ocsp 6 }
id-pkix-ocsp-service-locator OBJECT IDENTIFIER ::= { id-pkix-ocsp 7 }
id-pkix-ocsp-pref-sig-algs OBJECT IDENTIFIER ::= { id-pkix-ocsp 8 }
id-pkix-ocsp-extended-revoke OBJECT IDENTIFIER ::= { id-pkix-ocsp 9 }
END
<CODE ENDS>
Acknowledgements ๐ซถ
The authors of this document thank Mohit Sahni for his work to produce [RFC8954] ๐
The authors also thank Russ Housley, Corey Bonnell, Michael StJohns, Tomas Gustavsson, and Carl Wallace for their feedback and suggestions ๐ธ these people are literally the reason this doc slaps ๐
Author's Address โจ
Himanshu Sharma (editor)
Netskope Inc
2445 Augustine Dr 3rd floor
Santa Clara, California 95054
United States of America
Email: himanshu@netskope.com
URI: www.netskope.com
๐ฆ where this page comes from
- ietf: rfc9654 2024-08
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms