|
|
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
// are signed messages attesting to the validity of a certificate for a small
// period of time. This is used to manage revocation for X.509 certificates.
package ocsp // import "golang.org/x/crypto/ocsp"
import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "math/big" "strconv" "time" )
var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
// ResponseStatus contains the result of an OCSP request. See
// https://tools.ietf.org/html/rfc6960#section-2.3
type ResponseStatus int
const ( Success ResponseStatus = 0 Malformed ResponseStatus = 1 InternalError ResponseStatus = 2 TryLater ResponseStatus = 3 // Status code four is unused in OCSP. See
// https://tools.ietf.org/html/rfc6960#section-4.2.1
SignatureRequired ResponseStatus = 5 Unauthorized ResponseStatus = 6 )
func (r ResponseStatus) String() string { switch r { case Success: return "success" case Malformed: return "malformed" case InternalError: return "internal error" case TryLater: return "try later" case SignatureRequired: return "signature required" case Unauthorized: return "unauthorized" default: return "unknown OCSP status: " + strconv.Itoa(int(r)) } }
// ResponseError is an error that may be returned by ParseResponse to indicate
// that the response itself is an error, not just that its indicating that a
// certificate is revoked, unknown, etc.
type ResponseError struct { Status ResponseStatus }
func (r ResponseError) Error() string { return "ocsp: error from server: " + r.Status.String() }
// These are internal structures that reflect the ASN.1 structure of an OCSP
// response. See RFC 2560, section 4.2.
type certID struct { HashAlgorithm pkix.AlgorithmIdentifier NameHash []byte IssuerKeyHash []byte SerialNumber *big.Int }
// https://tools.ietf.org/html/rfc2560#section-4.1.1
type ocspRequest struct { TBSRequest tbsRequest }
type tbsRequest struct { Version int `asn1:"explicit,tag:0,default:0,optional"` RequestorName pkix.RDNSequence `asn1:"explicit,tag:1,optional"` RequestList []request }
type request struct { Cert certID }
type responseASN1 struct { Status asn1.Enumerated Response responseBytes `asn1:"explicit,tag:0,optional"` }
type responseBytes struct { ResponseType asn1.ObjectIdentifier Response []byte }
type basicResponse struct { TBSResponseData responseData SignatureAlgorithm pkix.AlgorithmIdentifier Signature asn1.BitString Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"` }
type responseData struct { Raw asn1.RawContent Version int `asn1:"optional,default:0,explicit,tag:0"` RawResponderID asn1.RawValue ProducedAt time.Time `asn1:"generalized"` Responses []singleResponse }
type singleResponse struct { CertID certID Good asn1.Flag `asn1:"tag:0,optional"` Revoked revokedInfo `asn1:"tag:1,optional"` Unknown asn1.Flag `asn1:"tag:2,optional"` ThisUpdate time.Time `asn1:"generalized"` NextUpdate time.Time `asn1:"generalized,explicit,tag:0,optional"` SingleExtensions []pkix.Extension `asn1:"explicit,tag:1,optional"` }
type revokedInfo struct { RevocationTime time.Time `asn1:"generalized"` Reason asn1.Enumerated `asn1:"explicit,tag:0,optional"` }
var ( oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} )
var hashOIDs = map[crypto.Hash]asn1.ObjectIdentifier{ crypto.SHA1: asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}), crypto.SHA256: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1}), crypto.SHA384: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2}), crypto.SHA512: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3}), }
// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
var signatureAlgorithmDetails = []struct { algo x509.SignatureAlgorithm oid asn1.ObjectIdentifier pubKeyAlgo x509.PublicKeyAlgorithm hash crypto.Hash }{ {x509.MD2WithRSA, oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */}, {x509.MD5WithRSA, oidSignatureMD5WithRSA, x509.RSA, crypto.MD5}, {x509.SHA1WithRSA, oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1}, {x509.SHA256WithRSA, oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256}, {x509.SHA384WithRSA, oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384}, {x509.SHA512WithRSA, oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512}, {x509.DSAWithSHA1, oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1}, {x509.DSAWithSHA256, oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256}, {x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1}, {x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256}, {x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384}, {x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512}, }
// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { var pubType x509.PublicKeyAlgorithm
switch pub := pub.(type) { case *rsa.PublicKey: pubType = x509.RSA hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureSHA256WithRSA sigAlgo.Parameters = asn1.RawValue{ Tag: 5, }
case *ecdsa.PublicKey: pubType = x509.ECDSA
switch pub.Curve { case elliptic.P224(), elliptic.P256(): hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 case elliptic.P384(): hashFunc = crypto.SHA384 sigAlgo.Algorithm = oidSignatureECDSAWithSHA384 case elliptic.P521(): hashFunc = crypto.SHA512 sigAlgo.Algorithm = oidSignatureECDSAWithSHA512 default: err = errors.New("x509: unknown elliptic curve") }
default: err = errors.New("x509: only RSA and ECDSA keys supported") }
if err != nil { return }
if requestedSigAlgo == 0 { return }
found := false for _, details := range signatureAlgorithmDetails { if details.algo == requestedSigAlgo { if details.pubKeyAlgo != pubType { err = errors.New("x509: requested SignatureAlgorithm does not match private key type") return } sigAlgo.Algorithm, hashFunc = details.oid, details.hash if hashFunc == 0 { err = errors.New("x509: cannot sign with hash function requested") return } found = true break } }
if !found { err = errors.New("x509: unknown SignatureAlgorithm") }
return }
// TODO(agl): this is taken from crypto/x509 and so should probably be exported
// from crypto/x509 or crypto/x509/pkix.
func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) x509.SignatureAlgorithm { for _, details := range signatureAlgorithmDetails { if oid.Equal(details.oid) { return details.algo } } return x509.UnknownSignatureAlgorithm }
// TODO(rlb): This is not taken from crypto/x509, but it's of the same general form.
func getHashAlgorithmFromOID(target asn1.ObjectIdentifier) crypto.Hash { for hash, oid := range hashOIDs { if oid.Equal(target) { return 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.
const ( // Good means that the certificate is valid.
Good = iota // Revoked means that the certificate has been deliberately revoked.
Revoked // Unknown means that the OCSP responder doesn't know about the certificate.
Unknown // ServerFailed is unused and was never used (see
// https://go-review.googlesource.com/#/c/18944). ParseResponse will
// return a ResponseError when an error response is parsed.
ServerFailed )
// The enumerated reasons for revoking a certificate. See RFC 5280.
const ( Unspecified = 0 KeyCompromise = 1 CACompromise = 2 AffiliationChanged = 3 Superseded = 4 CessationOfOperation = 5 CertificateHold = 6
RemoveFromCRL = 8 PrivilegeWithdrawn = 9 AACompromise = 10 )
// Request represents an OCSP request. See RFC 6960.
type Request struct { HashAlgorithm crypto.Hash IssuerNameHash []byte IssuerKeyHash []byte 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 { // Status is one of {Good, Revoked, Unknown}
Status int SerialNumber *big.Int ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time RevocationReason int Certificate *x509.Certificate // TBSResponseData contains the raw bytes of the signed response. If
// Certificate is nil then this can be used to verify Signature.
TBSResponseData []byte Signature []byte SignatureAlgorithm x509.SignatureAlgorithm
// IssuerHash is the hash used to compute the IssuerNameHash and IssuerKeyHash.
// Valid values are crypto.SHA1, crypto.SHA256, crypto.SHA384, and crypto.SHA512.
// If zero, the default is crypto.SHA1.
IssuerHash crypto.Hash
// RawResponderName optionally contains the DER-encoded subject of the
// responder certificate. Exactly one of RawResponderName and
// ResponderKeyHash is set.
RawResponderName []byte // ResponderKeyHash optionally contains the SHA-1 hash of the
// responder's public key. Exactly one of RawResponderName and
// ResponderKeyHash is set.
ResponderKeyHash []byte
// Extensions contains raw X.509 extensions from the singleExtensions field
// of the OCSP response. When parsing certificates, this can be used to
// extract non-critical extensions that are not parsed by this package. When
// marshaling OCSP responses, the Extensions field is ignored, see
// ExtraExtensions.
Extensions []pkix.Extension
// ExtraExtensions contains extensions to be copied, raw, into any marshaled
// OCSP response (in the singleExtensions field). Values override any
// extensions that would otherwise be produced based on the other fields. The
// ExtraExtensions field is not populated when parsing certificates, see
// Extensions.
ExtraExtensions []pkix.Extension }
// 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
// signature. That signature is checked by ParseResponse and only
// resp.Certificate remains to be validated.
func (resp *Response) CheckSignatureFrom(issuer *x509.Certificate) error { return issuer.CheckSignature(resp.SignatureAlgorithm, resp.TBSResponseData, resp.Signature) }
// ParseError results from an invalid OCSP response.
type ParseError string
func (p ParseError) Error() string { return string(p) }
// ParseRequest parses an OCSP request in DER form. It only supports
// requests for a single certificate. Signed requests are not supported.
// If a request includes a signature, it will result in a ParseError.
func ParseRequest(bytes []byte) (*Request, error) { var req ocspRequest rest, err := asn1.Unmarshal(bytes, &req) if err != nil { return nil, err } if len(rest) > 0 { return nil, ParseError("trailing data in OCSP request") }
if len(req.TBSRequest.RequestList) == 0 { return nil, ParseError("OCSP request contains no request body") } innerRequest := req.TBSRequest.RequestList[0]
hashFunc := getHashAlgorithmFromOID(innerRequest.Cert.HashAlgorithm.Algorithm) if hashFunc == crypto.Hash(0) { return nil, ParseError("OCSP request uses unknown hash function") }
return &Request{ HashAlgorithm: hashFunc, IssuerNameHash: innerRequest.Cert.NameHash, IssuerKeyHash: innerRequest.Cert.IssuerKeyHash, SerialNumber: innerRequest.Cert.SerialNumber, }, nil }
// ParseResponse parses an OCSP response in DER form. It only supports
// responses for a single certificate. If the response contains a certificate
// then the signature over the response is checked. If issuer is not nil then
// it will be used to validate the signature or embedded certificate.
//
// Invalid responses and parse failures will result in a ParseError.
// Error responses will result in a ResponseError.
func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) { return ParseResponseForCert(bytes, nil, issuer) }
// ParseResponseForCert parses an OCSP response in DER form and searches for a
// Response relating to cert. If such a Response is found and the OCSP response
// contains a certificate then the signature over the response is checked. If
// issuer is not nil then it will be used to validate the signature or embedded
// certificate.
//
// Invalid responses and parse failures will result in a ParseError.
// Error responses will result in a ResponseError.
func ParseResponseForCert(bytes []byte, cert, issuer *x509.Certificate) (*Response, error) { var resp responseASN1 rest, err := asn1.Unmarshal(bytes, &resp) if err != nil { return nil, err } if len(rest) > 0 { return nil, ParseError("trailing data in OCSP response") }
if status := ResponseStatus(resp.Status); status != Success { return nil, ResponseError{status} }
if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) { return nil, ParseError("bad OCSP response type") }
var basicResp basicResponse rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp) if err != nil { return nil, err }
if len(basicResp.Certificates) > 1 { return nil, ParseError("OCSP response contains bad number of certificates") }
if n := len(basicResp.TBSResponseData.Responses); n == 0 || cert == nil && n > 1 { return nil, ParseError("OCSP response contains bad number of responses") }
var singleResp singleResponse if cert == nil { singleResp = basicResp.TBSResponseData.Responses[0] } else { match := false for _, resp := range basicResp.TBSResponseData.Responses { if cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 { singleResp = resp match = true break } } if !match { return nil, ParseError("no response matching the supplied certificate") } }
ret := &Response{ TBSResponseData: basicResp.TBSResponseData.Raw, Signature: basicResp.Signature.RightAlign(), SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm), Extensions: singleResp.SingleExtensions, SerialNumber: singleResp.CertID.SerialNumber, ProducedAt: basicResp.TBSResponseData.ProducedAt, ThisUpdate: singleResp.ThisUpdate, NextUpdate: singleResp.NextUpdate, }
// Handle the ResponderID CHOICE tag. ResponderID can be flattened into
// TBSResponseData once https://go-review.googlesource.com/34503 has been
// released.
rawResponderID := basicResp.TBSResponseData.RawResponderID switch rawResponderID.Tag { case 1: // Name
var rdn pkix.RDNSequence if rest, err := asn1.Unmarshal(rawResponderID.Bytes, &rdn); err != nil || len(rest) != 0 { return nil, ParseError("invalid responder name") } ret.RawResponderName = rawResponderID.Bytes case 2: // KeyHash
if rest, err := asn1.Unmarshal(rawResponderID.Bytes, &ret.ResponderKeyHash); err != nil || len(rest) != 0 { return nil, ParseError("invalid responder key hash") } default: return nil, ParseError("invalid responder id tag") }
if len(basicResp.Certificates) > 0 { ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes) if err != nil { return nil, err }
if err := ret.CheckSignatureFrom(ret.Certificate); err != nil { return nil, ParseError("bad signature on embedded certificate: " + err.Error()) }
if issuer != nil { if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil { return nil, ParseError("bad OCSP signature: " + err.Error()) } } } else if issuer != nil { if err := ret.CheckSignatureFrom(issuer); err != nil { return nil, ParseError("bad OCSP signature: " + err.Error()) } }
for _, ext := range singleResp.SingleExtensions { if ext.Critical { return nil, ParseError("unsupported critical extension") } }
for h, oid := range hashOIDs { if singleResp.CertID.HashAlgorithm.Algorithm.Equal(oid) { ret.IssuerHash = h break } } if ret.IssuerHash == 0 { return nil, ParseError("unsupported issuer hash algorithm") }
switch { case bool(singleResp.Good): ret.Status = Good case bool(singleResp.Unknown): ret.Status = Unknown default: ret.Status = Revoked ret.RevokedAt = singleResp.Revoked.RevocationTime ret.RevocationReason = int(singleResp.Revoked.Reason) }
return ret, nil }
// RequestOptions contains options for constructing OCSP requests.
type RequestOptions struct { // Hash contains the hash function that should be used when
// constructing the OCSP request. If zero, SHA-1 will be used.
Hash crypto.Hash }
func (opts *RequestOptions) hash() crypto.Hash { if opts == nil || opts.Hash == 0 { // SHA-1 is nearly universally used in OCSP.
return crypto.SHA1 } return opts.Hash }
// CreateRequest returns a DER-encoded, OCSP request for the status of cert. If
// opts is nil then sensible defaults are used.
func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte, error) { hashFunc := opts.hash()
// 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
_, ok := hashOIDs[hashFunc] if !ok { return nil, x509.ErrUnsupportedAlgorithm }
if !hashFunc.Available() { return nil, x509.ErrUnsupportedAlgorithm } h := opts.hash().New()
var publicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil { return nil, err }
h.Write(publicKeyInfo.PublicKey.RightAlign()) issuerKeyHash := h.Sum(nil)
h.Reset() h.Write(issuer.RawSubject) issuerNameHash := h.Sum(nil)
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.
// The fields in the response are populated as follows:
//
// The responder cert is used to populate the responder's name field, and the
// certificate itself is provided alongside the OCSP response signature.
//
// The issuer cert is used to puplate the IssuerNameHash and IssuerKeyHash fields.
//
// The template is used to populate the SerialNumber, Status, RevokedAt,
// RevocationReason, ThisUpdate, and NextUpdate fields.
//
// If template.IssuerHash is not set, SHA1 will be used.
//
// The ProducedAt date is automatically set to the current date, to the nearest minute.
func CreateResponse(issuer, responderCert *x509.Certificate, template Response, priv crypto.Signer) ([]byte, error) { var publicKeyInfo struct { Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil { return nil, err }
if template.IssuerHash == 0 { template.IssuerHash = crypto.SHA1 } hashOID := getOIDFromHashAlgorithm(template.IssuerHash) if hashOID == nil { return nil, errors.New("unsupported issuer hash algorithm") }
if !template.IssuerHash.Available() { return nil, fmt.Errorf("issuer hash algorithm %v not linked into binary", template.IssuerHash) } h := template.IssuerHash.New() h.Write(publicKeyInfo.PublicKey.RightAlign()) issuerKeyHash := h.Sum(nil)
h.Reset() h.Write(issuer.RawSubject) issuerNameHash := h.Sum(nil)
innerResponse := singleResponse{ CertID: certID{ HashAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: hashOID, Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */}, }, NameHash: issuerNameHash, IssuerKeyHash: issuerKeyHash, SerialNumber: template.SerialNumber, }, ThisUpdate: template.ThisUpdate.UTC(), NextUpdate: template.NextUpdate.UTC(), SingleExtensions: template.ExtraExtensions, }
switch template.Status { case Good: innerResponse.Good = true case Unknown: innerResponse.Unknown = true case Revoked: innerResponse.Revoked = revokedInfo{ RevocationTime: template.RevokedAt.UTC(), Reason: asn1.Enumerated(template.RevocationReason), } }
rawResponderID := asn1.RawValue{ Class: 2, // context-specific
Tag: 1, // Name (explicit tag)
IsCompound: true, Bytes: responderCert.RawSubject, } tbsResponseData := responseData{ Version: 0, RawResponderID: rawResponderID, ProducedAt: time.Now().Truncate(time.Minute).UTC(), Responses: []singleResponse{innerResponse}, }
tbsResponseDataDER, err := asn1.Marshal(tbsResponseData) if err != nil { return nil, err }
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm) if err != nil { return nil, err }
responseHash := hashFunc.New() responseHash.Write(tbsResponseDataDER) signature, err := priv.Sign(rand.Reader, responseHash.Sum(nil), hashFunc) if err != nil { return nil, err }
response := basicResponse{ TBSResponseData: tbsResponseData, SignatureAlgorithm: signatureAlgorithm, Signature: asn1.BitString{ Bytes: signature, BitLength: 8 * len(signature), }, } if template.Certificate != nil { response.Certificates = []asn1.RawValue{ {FullBytes: template.Certificate.Raw}, } } responseDER, err := asn1.Marshal(response) if err != nil { return nil, err }
return asn1.Marshal(responseASN1{ Status: asn1.Enumerated(Success), Response: responseBytes{ ResponseType: idPKIXOCSPBasic, Response: responseDER, }, }) }
|