func (job *ProofVerifyJob) CheckSignature(cert *x509.Certificate) error { switch pub := cert.PublicKey.(type) { case *rsa.PublicKey: // cert.CheckSignature() uses PKCS1v15, not PSS. So we cannot use that on RSA h := sha256.New() h.Write(ProofSignatureLabel) h.Write(job.serverConfig) if err := rsa.VerifyPSS(pub, crypto.SHA256, h.Sum(nil), job.signature, nil); err != nil { return err } case *ecdsa.PublicKey: // TODO(hodduc): TEST needed if err := cert.CheckSignature(x509.ECDSAWithSHA256, job.serverConfig, job.signature); err != nil { return err } default: return errors.New("Unsupported Public key type") } return nil }
// 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 signatures or 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") } ret := &Response{ TBSResponseData: basicResp.TBSResponseData.Raw, Signature: basicResp.Signature.RightAlign(), SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm), } 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 OCSP signature") } if issuer != nil { if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil { return nil, ParseError("bad signature on embedded certificate") } } } else if issuer != nil { if err := ret.CheckSignatureFrom(issuer); err != nil { return nil, ParseError("bad OCSP signature") } } var r singleResponse for _, resp := range basicResp.TBSResponseData.Responses { if cert == nil || cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 { r = resp break } } for _, ext := range r.SingleExtensions { if ext.Critical { return nil, ParseError("unsupported critical extension") } } ret.Extensions = r.SingleExtensions ret.SerialNumber = r.CertID.SerialNumber switch { case bool(r.Good): ret.Status = Good case bool(r.Unknown): ret.Status = Unknown default: ret.Status = Revoked ret.RevokedAt = r.Revoked.RevocationTime ret.RevocationReason = int(r.Revoked.Reason) } ret.ProducedAt = basicResp.TBSResponseData.ProducedAt ret.ThisUpdate = r.ThisUpdate ret.NextUpdate = r.NextUpdate return ret, nil }
// 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) }
// 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 // signatures or parse failures will result in a ParseError. func ParseResponse(bytes []byte, 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") } ret := new(Response) if resp.Status != ocspSuccess { ret.Status = ServerFailed return ret, nil } 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 len(basicResp.TBSResponseData.Responses) != 1 { return nil, ParseError("OCSP response contains bad number of responses") } ret.TBSResponseData = basicResp.TBSResponseData.Raw ret.Signature = basicResp.Signature.RightAlign() ret.SignatureAlgorithm = getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm) 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 OCSP signature") } if issuer != nil { if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil { return nil, ParseError("bad signature on embedded certificate") } } } else if issuer != nil { if err := ret.CheckSignatureFrom(issuer); err != nil { return nil, ParseError("bad OCSP signature") } } r := basicResp.TBSResponseData.Responses[0] ret.SerialNumber = r.CertID.SerialNumber switch { case bool(r.Good): ret.Status = Good case bool(r.Unknown): ret.Status = Unknown default: ret.Status = Revoked ret.RevokedAt = r.Revoked.RevocationTime ret.RevocationReason = int(r.Revoked.Reason) } ret.ProducedAt = basicResp.TBSResponseData.ProducedAt ret.ThisUpdate = r.ThisUpdate ret.NextUpdate = r.NextUpdate return ret, nil }
// 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 signatures or 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") } ret := &Response{ TBSResponseData: basicResp.TBSResponseData.Raw, Signature: basicResp.Signature.RightAlign(), SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm), } // 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()) } } var r singleResponse for _, resp := range basicResp.TBSResponseData.Responses { if cert == nil || cert.SerialNumber.Cmp(resp.CertID.SerialNumber) == 0 { r = resp break } } for _, ext := range r.SingleExtensions { if ext.Critical { return nil, ParseError("unsupported critical extension") } } ret.Extensions = r.SingleExtensions ret.SerialNumber = r.CertID.SerialNumber for h, oid := range hashOIDs { if r.CertID.HashAlgorithm.Algorithm.Equal(oid) { ret.IssuerHash = h break } } if ret.IssuerHash == 0 { return nil, ParseError("unsupported issuer hash algorithm") } switch { case bool(r.Good): ret.Status = Good case bool(r.Unknown): ret.Status = Unknown default: ret.Status = Revoked ret.RevokedAt = r.Revoked.RevocationTime ret.RevocationReason = int(r.Revoked.Reason) } ret.ProducedAt = basicResp.TBSResponseData.ProducedAt ret.ThisUpdate = r.ThisUpdate ret.NextUpdate = r.NextUpdate return ret, nil }