From 0e69e08b8a4ea0fbd49846e211075f79ca0fff4f Mon Sep 17 00:00:00 2001 From: Roland Shoemaker Date: Sat, 13 Feb 2016 14:23:09 -0800 Subject: [PATCH] ocsp: add Request.Marshal method Tests that Marshaling a parsed response returns the same bytes as were parsed. Use Marshal in CreateRequest; still passes CreateRequest's golden test. Change-Id: I427ef8372d7b62c43b7718d7d90631d022377d32 Reviewed-on: https://go-review.googlesource.com/19488 Run-TryBot: Russ Cox Reviewed-by: Russ Cox --- ocsp/ocsp.go | 63 ++++++++++++++++++++++++++++++++--------------- ocsp/ocsp_test.go | 13 ++++++++++ 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/ocsp/ocsp.go b/ocsp/ocsp.go index 09367c0..a57e5f4 100644 --- a/ocsp/ocsp.go +++ b/ocsp/ocsp.go @@ -266,6 +266,15 @@ func getHashAlgorithmFromOID(target asn1.ObjectIdentifier) crypto.Hash { return crypto.Hash(0) } +func getOIDFromHashAlgorithm(target crypto.Hash) asn1.ObjectIdentifier { + for hash, oid := range hashOIDs { + if hash == target { + return oid + } + } + return nil +} + // This is the exposed reflection of the internal OCSP structures. // The status values that can be expressed in OCSP. See RFC 6960. @@ -305,6 +314,32 @@ type Request struct { SerialNumber *big.Int } +// Marshal marshals the OCSP request to ASN.1 DER encoded form. +func (req *Request) Marshal() ([]byte, error) { + hashAlg := getOIDFromHashAlgorithm(req.HashAlgorithm) + if hashAlg == nil { + return nil, errors.New("Unknown hash algorithm") + } + return asn1.Marshal(ocspRequest{ + tbsRequest{ + Version: 0, + RequestList: []request{ + { + Cert: certID{ + pkix.AlgorithmIdentifier{ + Algorithm: hashAlg, + Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */}, + }, + req.IssuerNameHash, + req.IssuerKeyHash, + req.SerialNumber, + }, + }, + }, + }, + }) +} + // Response represents an OCSP response containing a single SingleResponse. See // RFC 6960. type Response struct { @@ -512,8 +547,7 @@ func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte // OCSP seems to be the only place where these raw hash identifiers are // used. I took the following from // http://msdn.microsoft.com/en-us/library/ff635603.aspx - var hashOID asn1.ObjectIdentifier - hashOID, ok := hashOIDs[hashFunc] + _, ok := hashOIDs[hashFunc] if !ok { return nil, x509.ErrUnsupportedAlgorithm } @@ -538,24 +572,13 @@ func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte h.Write(issuer.RawSubject) issuerNameHash := h.Sum(nil) - return asn1.Marshal(ocspRequest{ - tbsRequest{ - Version: 0, - RequestList: []request{ - { - Cert: certID{ - pkix.AlgorithmIdentifier{ - Algorithm: hashOID, - Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */}, - }, - issuerNameHash, - issuerKeyHash, - cert.SerialNumber, - }, - }, - }, - }, - }) + req := &Request{ + HashAlgorithm: hashFunc, + IssuerNameHash: issuerNameHash, + IssuerKeyHash: issuerKeyHash, + SerialNumber: cert.SerialNumber, + } + return req.Marshal() } // CreateResponse returns a DER-encoded OCSP response with the specified contents. diff --git a/ocsp/ocsp_test.go b/ocsp/ocsp_test.go index 3386849..ae17ca2 100644 --- a/ocsp/ocsp_test.go +++ b/ocsp/ocsp_test.go @@ -159,6 +159,19 @@ func TestOCSPRequest(t *testing.T) { if got := decodedRequest.SerialNumber; got.Cmp(cert.SerialNumber) != 0 { t.Errorf("request.SerialNumber: got %x, want %x", got, cert.SerialNumber) } + + marshaledRequest, err := decodedRequest.Marshal() + if err != nil { + t.Fatal(err) + } + + if bytes.Compare(expectedBytes, marshaledRequest) != 0 { + t.Errorf( + "Marshaled request doesn't match expected: wanted %x, got %x", + expectedBytes, + marshaledRequest, + ) + } } func TestOCSPResponse(t *testing.T) {