github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/third_party/code.google.com/p/go.crypto/ocsp/ocsp.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
     6  // are signed messages attesting to the validity of a certificate for a small
     7  // period of time. This is used to manage revocation for X.509 certificates.
     8  package ocsp
     9  
    10  import (
    11  	"crypto"
    12  	"crypto/rsa"
    13  	_ "crypto/sha1"
    14  	"crypto/x509"
    15  	"crypto/x509/pkix"
    16  	"encoding/asn1"
    17  	"time"
    18  )
    19  
    20  var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
    21  var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
    22  
    23  // These are internal structures that reflect the ASN.1 structure of an OCSP
    24  // response. See RFC 2560, section 4.2.
    25  
    26  const (
    27  	ocspSuccess       = 0
    28  	ocspMalformed     = 1
    29  	ocspInternalError = 2
    30  	ocspTryLater      = 3
    31  	ocspSigRequired   = 4
    32  	ocspUnauthorized  = 5
    33  )
    34  
    35  type certID struct {
    36  	HashAlgorithm pkix.AlgorithmIdentifier
    37  	NameHash      []byte
    38  	IssuerKeyHash []byte
    39  	SerialNumber  asn1.RawValue
    40  }
    41  
    42  type responseASN1 struct {
    43  	Status   asn1.Enumerated
    44  	Response responseBytes `asn1:"explicit,tag:0"`
    45  }
    46  
    47  type responseBytes struct {
    48  	ResponseType asn1.ObjectIdentifier
    49  	Response     []byte
    50  }
    51  
    52  type basicResponse struct {
    53  	TBSResponseData    responseData
    54  	SignatureAlgorithm pkix.AlgorithmIdentifier
    55  	Signature          asn1.BitString
    56  	Certificates       []asn1.RawValue `asn1:"explicit,tag:0,optional"`
    57  }
    58  
    59  type responseData struct {
    60  	Raw           asn1.RawContent
    61  	Version       int              `asn1:"optional,default:1,explicit,tag:0"`
    62  	RequestorName pkix.RDNSequence `asn1:"optional,explicit,tag:1"`
    63  	KeyHash       []byte           `asn1:"optional,explicit,tag:2"`
    64  	ProducedAt    time.Time
    65  	Responses     []singleResponse
    66  }
    67  
    68  type singleResponse struct {
    69  	CertID     certID
    70  	Good       asn1.Flag   `asn1:"explicit,tag:0,optional"`
    71  	Revoked    revokedInfo `asn1:"explicit,tag:1,optional"`
    72  	Unknown    asn1.Flag   `asn1:"explicit,tag:2,optional"`
    73  	ThisUpdate time.Time
    74  	NextUpdate time.Time `asn1:"explicit,tag:0,optional"`
    75  }
    76  
    77  type revokedInfo struct {
    78  	RevocationTime time.Time
    79  	Reason         int `asn1:"explicit,tag:0,optional"`
    80  }
    81  
    82  // This is the exposed reflection of the internal OCSP structures.
    83  
    84  const (
    85  	// Good means that the certificate is valid.
    86  	Good = iota
    87  	// Revoked means that the certificate has been deliberately revoked.
    88  	Revoked = iota
    89  	// Unknown means that the OCSP responder doesn't know about the certificate.
    90  	Unknown = iota
    91  	// ServerFailed means that the OCSP responder failed to process the request.
    92  	ServerFailed = iota
    93  )
    94  
    95  // Response represents an OCSP response. See RFC 2560.
    96  type Response struct {
    97  	// Status is one of {Good, Revoked, Unknown, ServerFailed}
    98  	Status                                        int
    99  	SerialNumber                                  []byte
   100  	ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
   101  	RevocationReason                              int
   102  	Certificate                                   *x509.Certificate
   103  }
   104  
   105  // ParseError results from an invalid OCSP response.
   106  type ParseError string
   107  
   108  func (p ParseError) Error() string {
   109  	return string(p)
   110  }
   111  
   112  // ParseResponse parses an OCSP response in DER form. It only supports
   113  // responses for a single certificate and only those using RSA signatures.
   114  // Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
   115  // Signature errors or parse failures will result in a ParseError.
   116  func ParseResponse(bytes []byte) (*Response, error) {
   117  	var resp responseASN1
   118  	rest, err := asn1.Unmarshal(bytes, &resp)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	if len(rest) > 0 {
   123  		return nil, ParseError("trailing data in OCSP response")
   124  	}
   125  
   126  	ret := new(Response)
   127  	if resp.Status != ocspSuccess {
   128  		ret.Status = ServerFailed
   129  		return ret, nil
   130  	}
   131  
   132  	if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
   133  		return nil, ParseError("bad OCSP response type")
   134  	}
   135  
   136  	var basicResp basicResponse
   137  	rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  
   142  	if len(basicResp.Certificates) != 1 {
   143  		return nil, ParseError("OCSP response contains bad number of certificates")
   144  	}
   145  
   146  	if len(basicResp.TBSResponseData.Responses) != 1 {
   147  		return nil, ParseError("OCSP response contains bad number of responses")
   148  	}
   149  
   150  	ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
   156  		return nil, x509.ErrUnsupportedAlgorithm
   157  	}
   158  
   159  	hashType := crypto.SHA1
   160  	h := hashType.New()
   161  
   162  	pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
   163  	h.Write(basicResp.TBSResponseData.Raw)
   164  	digest := h.Sum(nil)
   165  	signature := basicResp.Signature.RightAlign()
   166  
   167  	if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
   168  		return nil, ParseError("bad OCSP signature")
   169  	}
   170  
   171  	r := basicResp.TBSResponseData.Responses[0]
   172  
   173  	ret.SerialNumber = r.CertID.SerialNumber.Bytes
   174  
   175  	switch {
   176  	case bool(r.Good):
   177  		ret.Status = Good
   178  	case bool(r.Unknown):
   179  		ret.Status = Unknown
   180  	default:
   181  		ret.Status = Revoked
   182  		ret.RevokedAt = r.Revoked.RevocationTime
   183  		ret.RevocationReason = r.Revoked.Reason
   184  	}
   185  
   186  	ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
   187  	ret.ThisUpdate = r.ThisUpdate
   188  	ret.NextUpdate = r.NextUpdate
   189  
   190  	return ret, nil
   191  }