func (i *Info) Before(t time.Time) bool {
	return i.genTimeMax().Before(t)
}
Before checks if the latest time the signature could have been generated at
is before the specified time. For example, you might check that a signature
was made *before* a certificate's not-after date.
package timestamp
import (
	"bytes"
	"crypto"
	"crypto/rand"
	"crypto/x509/pkix"
	"encoding/asn1"
	"fmt"
	"io"
	"math/big"
	"net/http"
	"strings"
	"time"
	"github.com/github/ietf-cms/oid"
	"github.com/github/ietf-cms/protocol"
)
type HTTPClient interface {
	Do(*http.Request) (*http.Response, error)
}
var DefaultHTTPClient = HTTPClient(http.DefaultClient)
const (
	contentTypeTSQuery = "application/timestamp-query"
	contentTypeTSReply = "application/timestamp-reply"
	nonceBytes         = 16
)
func GenerateNonce() *big.Int {
	buf := make([]byte, nonceBytes)
	if _, err := rand.Read(buf); err != nil {
		panic(err)
	}
	return new(big.Int).SetBytes(buf[:])
}
type Request struct {
	Version        int
	MessageImprint MessageImprint
	ReqPolicy      asn1.ObjectIdentifier `asn1:"optional"`
	Nonce          *big.Int              `asn1:"optional"`
	CertReq        bool                  `asn1:"optional,default:false"`
	Extensions     []pkix.Extension      `asn1:"tag:1,optional"`
}
func (req Request) Matches(tsti Info) bool {
	if !req.MessageImprint.Equal(tsti.MessageImprint) {
		return false
	}
	if req.Nonce != nil && tsti.Nonce == nil || req.Nonce.Cmp(tsti.Nonce) != 0 {
		return false
	}
	return true
}
func (req Request) Do(url string) (Response, error) {
	var nilResp Response
	reqDER, err := asn1.Marshal(req)
	if err != nil {
		return nilResp, err
	}
	httpReq, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(reqDER))
	if err != nil {
		return nilResp, err
	}
	httpReq.Header.Add("Content-Type", contentTypeTSQuery)
	httpResp, err := DefaultHTTPClient.Do(httpReq)
	if err != nil {
		return nilResp, err
	}
	if ct := httpResp.Header.Get("Content-Type"); ct != contentTypeTSReply {
		return nilResp, fmt.Errorf("Bad content-type: %s", ct)
	}
	buf := bytes.NewBuffer(make([]byte, 0, httpResp.ContentLength))
	if _, err = io.Copy(buf, httpResp.Body); err != nil {
		return nilResp, err
	}
	return ParseResponse(buf.Bytes())
}
type Response struct {
	Status         PKIStatusInfo
	TimeStampToken protocol.ContentInfo `asn1:"optional"`
}
func ParseResponse(ber []byte) (Response, error) {
	var resp Response
	der, err := protocol.BER2DER(ber)
	if err != nil {
		return resp, err
	}
	rest, err := asn1.Unmarshal(der, &resp)
	if err != nil {
		return resp, err
	}
	if len(rest) > 0 {
		return resp, protocol.ErrTrailingData
	}
	return resp, nil
}
func (r Response) Info() (Info, error) {
	var nilInfo Info
	if err := r.Status.GetError(); err != nil {
		return nilInfo, err
	}
	sd, err := r.TimeStampToken.SignedDataContent()
	if err != nil {
		return nilInfo, err
	}
	return ParseInfo(sd.EncapContentInfo)
}
type PKIStatusInfo struct {
	Status       int
	StatusString PKIFreeText    `asn1:"optional"`
	FailInfo     asn1.BitString `asn1:"optional"`
}
func (si PKIStatusInfo) GetError() error {
	if si.Status == 0 {
		return nil
	}
	return si
}
func (si PKIStatusInfo) Error() string {
	fiStr := ""
	if si.FailInfo.BitLength > 0 {
		fibin := make([]byte, si.FailInfo.BitLength)
		for i := range fibin {
			if si.FailInfo.At(i) == 1 {
				fibin[i] = byte('1')
			} else {
				fibin[i] = byte('0')
			}
		}
		fiStr = fmt.Sprintf(" FailInfo(0b%s)", string(fibin))
	}
	statusStr := ""
	if len(si.StatusString) > 0 {
		if strs, err := si.StatusString.Strings(); err == nil {
			statusStr = fmt.Sprintf(" StatusString(%s)", strings.Join(strs, ","))
		}
	}
	return fmt.Sprintf("Bad TimeStampResp: Status(%d)%s%s", si.Status, statusStr, fiStr)
}
type PKIFreeText []asn1.RawValue
func (ft PKIFreeText) Append(t string) PKIFreeText {
	return append(ft, asn1.RawValue{
		Class: asn1.ClassUniversal,
		Tag:   asn1.TagUTF8String,
		Bytes: []byte(t),
	})
}
func (ft PKIFreeText) Strings() ([]string, error) {
	strs := make([]string, len(ft))
	for i := range ft {
		if rest, err := asn1.Unmarshal(ft[i].FullBytes, &strs[i]); err != nil {
			return nil, err
		} else if len(rest) != 0 {
			return nil, protocol.ErrTrailingData
		}
	}
	return strs, nil
}
type Info struct {
	Version        int
	Policy         asn1.ObjectIdentifier
	MessageImprint MessageImprint
	SerialNumber   *big.Int
	GenTime        time.Time        `asn1:"generalized"`
	Accuracy       Accuracy         `asn1:"optional"`
	Ordering       bool             `asn1:"optional,default:false"`
	Nonce          *big.Int         `asn1:"optional"`
	TSA            asn1.RawValue    `asn1:"tag:0,optional"`
	Extensions     []pkix.Extension `asn1:"tag:1,optional"`
}
func ParseInfo(eci protocol.EncapsulatedContentInfo) (Info, error) {
	i := Info{}
	if !eci.EContentType.Equal(oid.ContentTypeTSTInfo) {
		return i, protocol.ErrWrongType
	}
	ecval, err := eci.EContentValue()
	if err != nil {
		return i, err
	}
	if ecval == nil {
		return i, protocol.ASN1Error{Message: "missing EContent for non data type"}
	}
	if rest, err := asn1.Unmarshal(ecval, &i); err != nil {
		return i, err
	} else if len(rest) > 0 {
		return i, protocol.ErrTrailingData
	}
	return i, nil
}