ソースを参照

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>
Richard Barnes 10 年 前
コミット
5b330e8ba0
2 ファイル変更39 行追加20 行削除
  1. 36 17
      ocsp/ocsp.go
  2. 3 3
      ocsp/ocsp_test.go

+ 36 - 17
ocsp/ocsp.go

@@ -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
ocsp/ocsp_test.go

@@ -333,9 +333,9 @@ const ocspResponseWithoutCertHex = "308201d40a0100a08201cd308201c906092b06010505
 	"20a1a65c7f0b6427a224b3c98edd96b9b61f706099951188b0289555ad30a216fb774651" +
 	"5a35fca2e054dfa8"
 
-const ocspRequestHex = "30563054a003020100304d304b3049300906052b0e03021a05000414c0fe0278fc991888" +
-	"91b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210" +
-	"017f77deb3bcbb235d44ccc7dba62e72"
+const ocspRequestHex = "3051304f304d304b3049300906052b0e03021a05000414c0fe0278fc99188891b3f212e9" +
+	"c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210017f77deb3" +
+	"bcbb235d44ccc7dba62e72"
 
 const leafCertHex = "308203c830820331a0030201020210017f77deb3bcbb235d44ccc7dba62e72300d06092a" +
 	"864886f70d01010505003081ba311f301d060355040a1316566572695369676e20547275" +