func (b *Bolt) Revoked(caName string) ([]pkix.RevokedCertificate, error) {
	var revokedCerts []pkix.RevokedCertificate
	if err := b.DB.View(func(tx *bolt.Tx) error {
		root := tx.Bucket([]byte(caName))
		if root == nil {
			return fmt.Errorf("%v bucket does not exist", caName)
		}
		revoked := root.Bucket(revokedBucketKey)
		if revoked == nil {
			return nil
		}
		return revoked.ForEach(func(k, v []byte) error {
			sn := big.NewInt(0)
			if err := sn.GobDecode(k); err != nil {
				return fmt.Errorf("failed gob decoding serial number: %v", err)
			}
			t := time.Time{}
			if err := t.GobDecode(v); err != nil {
				return fmt.Errorf("failed gob decoding revocation time: %v", err)
			}
			revokedCerts = append(revokedCerts, pkix.RevokedCertificate{
				SerialNumber:   sn,
				RevocationTime: t,
			})
			return nil
		})
	}); err != nil {
		return nil, err
	}
	return revokedCerts, nil
}
Revoked returns a list of revoked certificates.
package store
import (
	"crypto/x509/pkix"
	"errors"
	"math/big"
	"time"
	"fmt"
	"github.com/boltdb/bolt"
	"github.com/google/easypki/pkg/certificate"
)
var (
	keysBucketKey    = []byte("keys")
	certsBucketKey   = []byte("certs")
	revokedBucketKey = []byte("revoked")
)
var (
	ErrDoesNotExist = errors.New("does not exist")
)
type Bolt struct {
	DB *bolt.DB
}
func (b *Bolt) Add(caName, name string, isCa bool, key, cert []byte) error {
	return b.DB.Update(func(tx *bolt.Tx) error {
		kb, cb, err := buckets(tx, caName)
		if err != nil {
			return err
		}
		k := []byte(name)
		if err := kb.Put(k, key); err != nil {
			return fmt.Errorf("failed puting %v key into %v keys bucket: %v", name, caName, err)
		}
		if err := cb.Put(k, cert); err != nil {
			return fmt.Errorf("failed puting %v cert into %v certs bucket: %v", name, caName, err)
		}
		if isCa && name != caName {
			kb, cb, err = buckets(tx, name)
			if err != nil {
				return err
			}
			if err := kb.Put(k, key); err != nil {
				return fmt.Errorf("failed puting %v key into %v keys bucket: %v", name, name, err)
			}
			if err := cb.Put(k, cert); err != nil {
				return fmt.Errorf("failed puting %v cert into %v certs bucket: %v", name, name, err)
			}
		}
		return nil
	})
}
func (b *Bolt) Fetch(caName, name string) ([]byte, []byte, error) {
	var key, cert []byte
	err := b.DB.View(func(tx *bolt.Tx) error {
		rb := tx.Bucket([]byte(caName))
		if rb == nil {
			return fmt.Errorf("%v bucket does not exist", caName)
		}
		kb := rb.Bucket(keysBucketKey)
		if kb == nil {
			return fmt.Errorf("%v keys bucket does not exist", caName)
		}
		cb := rb.Bucket(certsBucketKey)
		if cb == nil {
			return fmt.Errorf("%v certs bucket does not exist", caName)
		}
		k := []byte(name)
		key = kb.Get(k)
		cert = cb.Get(k)
		if key == nil || cert == nil {
			return ErrDoesNotExist
		}
		return nil
	})
	return key, cert, err
}
func (b *Bolt) Update(caName string, sn *big.Int, st certificate.State) error {
	if st != certificate.Revoked {
		return fmt.Errorf("unsupported update for certificate state %v", st)
	}
	return b.DB.Update(func(tx *bolt.Tx) error {
		root, err := tx.CreateBucketIfNotExists([]byte(caName))
		if err != nil {
			return fmt.Errorf("failed getting %v bucket: %v", caName, err)
		}
		revoked, err := root.CreateBucketIfNotExists(revokedBucketKey)
		if err != nil {
			return fmt.Errorf("failed getting %v revoked bucket: %v", root, err)
		}
		t, err := time.Now().GobEncode()
		if err != nil {
			return fmt.Errorf("failed gob encoding current time: %v", err)
		}
		k, err := sn.GobEncode()
		if err != nil {
			return fmt.Errorf("failed gob encoding serial number %v: %v", sn, err)
		}
		if err := revoked.Put(k, t); err != nil {
			return fmt.Errorf("failed adding serial number %v to the %v revoked bucket: %v", sn, caName, err)
		}
		return nil
	})
}