ocsp: pre-serialized responses and improved ASN.1
OCSP responders sometimes rely on pre-generated responses to increase performance. In such cases, RFC 5019 allows responders to respond with responseStatus unauthorized if they do not have a pre-generated response for a certificate. This patch provides a pre-serialized unauthorized response. This change also updates the serialization of OCSP responses so that the resulting DER encoding is compatible with other parsers. Note: This change depends on updates to encoding/asn1 to improve handling of flags and time values. https://go-review.googlesource.com/#/c/5970/ Change-Id: I77e042de6535a70b0996e058cb38a00076a16dd4 Reviewed-on: https://go-review.googlesource.com/4121 Reviewed-by: Adam Langley <agl@golang.org>
This commit is contained in:
committed by
Adam Langley
parent
ecf53cc131
commit
5b330e8ba0
+36
-17
@@ -49,7 +49,7 @@ type ocspRequest struct {
|
||||
}
|
||||
|
||||
type tbsRequest struct {
|
||||
Version int `asn1:"explicit,tag:0,default:0"`
|
||||
Version int `asn1:"explicit,tag:0,default:0,optional"`
|
||||
RequestorName pkix.RDNSequence `asn1:"explicit,tag:1,optional"`
|
||||
RequestList []request
|
||||
}
|
||||
@@ -76,26 +76,26 @@ type basicResponse struct {
|
||||
}
|
||||
|
||||
type responseData struct {
|
||||
Raw asn1.RawContent
|
||||
Version int `asn1:"optional,default:1,explicit,tag:0"`
|
||||
ResponderName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
|
||||
KeyHash []byte `asn1:"optional,explicit,tag:2"`
|
||||
ProducedAt time.Time
|
||||
Responses []singleResponse
|
||||
Raw asn1.RawContent
|
||||
Version int `asn1:"optional,default:1,explicit,tag:0"`
|
||||
RawResponderName asn1.RawValue `asn1:"optional,explicit,tag:1"`
|
||||
KeyHash []byte `asn1:"optional,explicit,tag:2"`
|
||||
ProducedAt time.Time `asn1:"generalized"`
|
||||
Responses []singleResponse
|
||||
}
|
||||
|
||||
type singleResponse struct {
|
||||
CertID certID
|
||||
Good asn1.Flag `asn1:"explicit,tag:0,optional"`
|
||||
Good asn1.Flag `asn1:"tag:0,optional"`
|
||||
Revoked revokedInfo `asn1:"explicit,tag:1,optional"`
|
||||
Unknown asn1.Flag `asn1:"explicit,tag:2,optional"`
|
||||
ThisUpdate time.Time
|
||||
NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
|
||||
Unknown asn1.Flag `asn1:"tag:2,optional"`
|
||||
ThisUpdate time.Time `asn1:"generalized"`
|
||||
NextUpdate time.Time `asn1:"generalized,explicit,tag:0,optional"`
|
||||
}
|
||||
|
||||
type revokedInfo struct {
|
||||
RevocationTime time.Time
|
||||
Reason int `asn1:"explicit,tag:0,optional"`
|
||||
RevocationTime time.Time `asn1:"generalized"`
|
||||
Reason int `asn1:"explicit,tag:0,optional"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -264,6 +264,18 @@ type Response struct {
|
||||
SignatureAlgorithm x509.SignatureAlgorithm
|
||||
}
|
||||
|
||||
// These are pre-serialized error responses for the various non-success codes
|
||||
// defined by OCSP. The Unauthorized code in particular can be used by an OCSP
|
||||
// responder that supports only pre-signed responses as a response to requests
|
||||
// for certificates with unknown status. See RFC 5019.
|
||||
var (
|
||||
MalformedRequestErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x01}
|
||||
InternalErrorErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x02}
|
||||
TryLaterErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x03}
|
||||
SigRequredErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x05}
|
||||
UnauthorizedErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x06}
|
||||
)
|
||||
|
||||
// CheckSignatureFrom checks that the signature in resp is a valid signature
|
||||
// from issuer. This should only be used if resp.Certificate is nil. Otherwise,
|
||||
// the OCSP response contained an intermediate certificate that created the
|
||||
@@ -517,15 +529,22 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
|
||||
innerResponse.Unknown = true
|
||||
case Revoked:
|
||||
innerResponse.Revoked = revokedInfo{
|
||||
RevocationTime: template.RevokedAt,
|
||||
RevocationTime: template.RevokedAt.UTC(),
|
||||
Reason: template.RevocationReason,
|
||||
}
|
||||
}
|
||||
|
||||
responderName := asn1.RawValue{
|
||||
Class: 2, // context-specific
|
||||
Tag: 1, // explicit tag
|
||||
IsCompound: true,
|
||||
Bytes: responderCert.RawSubject,
|
||||
}
|
||||
tbsResponseData := responseData{
|
||||
ResponderName: responderCert.Subject.ToRDNSequence(),
|
||||
ProducedAt: time.Now().Truncate(time.Minute),
|
||||
Responses: []singleResponse{innerResponse},
|
||||
Version: 0,
|
||||
RawResponderName: responderName,
|
||||
ProducedAt: time.Now().Truncate(time.Minute).UTC(),
|
||||
Responses: []singleResponse{innerResponse},
|
||||
}
|
||||
|
||||
tbsResponseDataDER, err := asn1.Marshal(tbsResponseData)
|
||||
|
||||
+3
-3
@@ -333,9 +333,9 @@ const ocspResponseWithoutCertHex = "308201d40a0100a08201cd308201c906092b06010505
|
||||
"20a1a65c7f0b6427a224b3c98edd96b9b61f706099951188b0289555ad30a216fb774651" +
|
||||
"5a35fca2e054dfa8"
|
||||
|
||||
const ocspRequestHex = "30563054a003020100304d304b3049300906052b0e03021a05000414c0fe0278fc991888" +
|
||||
"91b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210" +
|
||||
"017f77deb3bcbb235d44ccc7dba62e72"
|
||||
const ocspRequestHex = "3051304f304d304b3049300906052b0e03021a05000414c0fe0278fc99188891b3f212e9" +
|
||||
"c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210017f77deb3" +
|
||||
"bcbb235d44ccc7dba62e72"
|
||||
|
||||
const leafCertHex = "308203c830820331a0030201020210017f77deb3bcbb235d44ccc7dba62e72300d06092a" +
|
||||
"864886f70d01010505003081ba311f301d060355040a1316566572695369676e20547275" +
|
||||
|
||||
Reference in New Issue
Block a user