Skip to content

Commit b9db5ad

Browse files
crypto/ocsp: Add Marshal() method to Response type
Response.Marshal() returns a DER encoded OCSP response
1 parent 530e935 commit b9db5ad

File tree

2 files changed

+119
-33
lines changed

2 files changed

+119
-33
lines changed

ocsp/ocsp.go

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ type basicResponse struct {
115115
Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
116116
}
117117

118+
type basicResponseRawTBS struct {
119+
TBSResponseData asn1.RawValue
120+
SignatureAlgorithm pkix.AlgorithmIdentifier
121+
Signature asn1.BitString
122+
Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
123+
}
124+
118125
type responseData struct {
119126
Raw asn1.RawContent
120127
Version int `asn1:"optional,default:0,explicit,tag:0"`
@@ -181,32 +188,50 @@ var signatureAlgorithmDetails = []struct {
181188
{x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
182189
}
183190

191+
func signingParamsForAlgo(requestedSigAlgo x509.SignatureAlgorithm) (sigAlgo pkix.AlgorithmIdentifier, err error) {
192+
found := false
193+
for _, details := range signatureAlgorithmDetails {
194+
if details.algo == requestedSigAlgo {
195+
found = true
196+
sigAlgo.Algorithm = details.oid
197+
if details.pubKeyAlgo == x509.RSA {
198+
sigAlgo.Parameters = asn1.RawValue{
199+
Tag: 5,
200+
}
201+
}
202+
}
203+
}
204+
if !found {
205+
err = fmt.Errorf("invalid requestedSigAlgo: %s", requestedSigAlgo)
206+
}
207+
return
208+
}
209+
184210
// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
185-
func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
211+
// NOTE(nej) - modified this a bit to return x509.SignatureAlgorithm instead of the pkix.AlgorithmIdentifier, see
212+
// signingParamsForAlgo above.
213+
func signingAlgoForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo x509.SignatureAlgorithm, err error) {
186214
var pubType x509.PublicKeyAlgorithm
187215

188216
switch pub := pub.(type) {
189217
case *rsa.PublicKey:
190218
pubType = x509.RSA
191219
hashFunc = crypto.SHA256
192-
sigAlgo.Algorithm = oidSignatureSHA256WithRSA
193-
sigAlgo.Parameters = asn1.RawValue{
194-
Tag: 5,
195-
}
220+
sigAlgo = x509.SHA256WithRSA
196221

197222
case *ecdsa.PublicKey:
198223
pubType = x509.ECDSA
199224

200225
switch pub.Curve {
201226
case elliptic.P224(), elliptic.P256():
202227
hashFunc = crypto.SHA256
203-
sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
228+
sigAlgo = x509.ECDSAWithSHA256
204229
case elliptic.P384():
205230
hashFunc = crypto.SHA384
206-
sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
231+
sigAlgo = x509.ECDSAWithSHA384
207232
case elliptic.P521():
208233
hashFunc = crypto.SHA512
209-
sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
234+
sigAlgo = x509.ECDSAWithSHA512
210235
default:
211236
err = errors.New("x509: unknown elliptic curve")
212237
}
@@ -230,7 +255,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
230255
err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
231256
return
232257
}
233-
sigAlgo.Algorithm, hashFunc = details.oid, details.hash
258+
sigAlgo, hashFunc = details.algo, details.hash
234259
if hashFunc == 0 {
235260
err = errors.New("x509: cannot sign with hash function requested")
236261
return
@@ -407,6 +432,42 @@ func (resp *Response) CheckSignatureFrom(issuer *x509.Certificate) error {
407432
return issuer.CheckSignature(resp.SignatureAlgorithm, resp.TBSResponseData, resp.Signature)
408433
}
409434

435+
// Marshal marshals the OCSP response to ASN.1 DER encoded form
436+
func (resp *Response) Marshal() ([]byte, error) {
437+
438+
signatureAlgorithm, err := signingParamsForAlgo(resp.SignatureAlgorithm)
439+
if err != nil {
440+
return nil, err
441+
}
442+
response := basicResponseRawTBS{
443+
TBSResponseData: asn1.RawValue{FullBytes: resp.TBSResponseData},
444+
SignatureAlgorithm: signatureAlgorithm,
445+
Signature: asn1.BitString{
446+
Bytes: resp.Signature,
447+
BitLength: 8 * len(resp.Signature),
448+
},
449+
}
450+
451+
if resp.Certificate != nil {
452+
response.Certificates = []asn1.RawValue{
453+
{FullBytes: resp.Certificate.Raw},
454+
}
455+
}
456+
457+
responseDER, err := asn1.Marshal(response)
458+
if err != nil {
459+
return nil, err
460+
}
461+
462+
return asn1.Marshal(responseASN1{
463+
Status: asn1.Enumerated(Success),
464+
Response: responseBytes{
465+
ResponseType: idPKIXOCSPBasic,
466+
Response: responseDER,
467+
},
468+
})
469+
}
470+
410471
// ParseError results from an invalid OCSP response.
411472
type ParseError string
412473

@@ -744,7 +805,7 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
744805
return nil, err
745806
}
746807

747-
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
808+
hashFunc, sigAlgo, err := signingAlgoForPublicKey(priv.Public(), template.SignatureAlgorithm)
748809
if err != nil {
749810
return nil, err
750811
}
@@ -756,29 +817,12 @@ func CreateResponse(issuer, responderCert *x509.Certificate, template Response,
756817
return nil, err
757818
}
758819

759-
response := basicResponse{
760-
TBSResponseData: tbsResponseData,
761-
SignatureAlgorithm: signatureAlgorithm,
762-
Signature: asn1.BitString{
763-
Bytes: signature,
764-
BitLength: 8 * len(signature),
765-
},
766-
}
767-
if template.Certificate != nil {
768-
response.Certificates = []asn1.RawValue{
769-
{FullBytes: template.Certificate.Raw},
770-
}
771-
}
772-
responseDER, err := asn1.Marshal(response)
773-
if err != nil {
774-
return nil, err
820+
resp := &Response{
821+
Certificate: template.Certificate,
822+
TBSResponseData: tbsResponseDataDER,
823+
Signature: signature,
824+
SignatureAlgorithm: sigAlgo,
775825
}
776826

777-
return asn1.Marshal(responseASN1{
778-
Status: asn1.Enumerated(Success),
779-
Response: responseBytes{
780-
ResponseType: idPKIXOCSPBasic,
781-
Response: responseDER,
782-
},
783-
})
827+
return resp.Marshal()
784828
}

ocsp/ocsp_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,48 @@ func TestOCSPDecode(t *testing.T) {
7171
}
7272
}
7373

74+
func TestOCSPResponseMarshal(t *testing.T) {
75+
for _, tData := range []struct {
76+
name string
77+
ocspRespHex string
78+
certHex string
79+
}{
80+
{"Resp", ocspResponseHex, ""},
81+
{"RespWithoutCert", ocspResponseWithoutCertHex, ""},
82+
{"RespWithExt", ocspResponseWithExtensionHex, ""},
83+
{"MultiResp", ocspMultiResponseHex, ocspMultiResponseCertHex},
84+
} {
85+
t.Run(tData.name, func(t *testing.T) {
86+
responseBytes, _ := hex.DecodeString(tData.ocspRespHex)
87+
var crt *x509.Certificate
88+
if len(tData.certHex) > 0 {
89+
crtBytes, _ := hex.DecodeString(tData.certHex)
90+
var err error
91+
crt, err = x509.ParseCertificate(crtBytes)
92+
if err != nil {
93+
t.Errorf("error parsing certificate: %s", err)
94+
return
95+
}
96+
}
97+
resp, err := ParseResponseForCert(responseBytes, crt, nil)
98+
if err != nil {
99+
t.Errorf("unexpected parse error: %s", err)
100+
return
101+
}
102+
103+
marshalBytes, err := resp.Marshal()
104+
if err != nil {
105+
t.Errorf("unexpected error on marshal: %s", err)
106+
return
107+
}
108+
if !bytes.Equal(responseBytes, marshalBytes) {
109+
t.Errorf("bytes not equal on marshal")
110+
}
111+
})
112+
}
113+
114+
}
115+
74116
func TestOCSPDecodeWithoutCert(t *testing.T) {
75117
responseBytes, _ := hex.DecodeString(ocspResponseWithoutCertHex)
76118
_, err := ParseResponse(responseBytes, nil)

0 commit comments

Comments
 (0)