Add a blocked keys table, and use it (#4773)

Fixes #4712 and fixes #4711.
This commit is contained in:
Roland Bracewell Shoemaker 2020-04-15 13:42:51 -07:00 committed by GitHub
parent 5254844ba2
commit 9df97cbf06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 744 additions and 167 deletions

View File

@ -669,6 +669,7 @@ func (ca *CertificateAuthorityImpl) issuePrecertificateInner(ctx context.Context
}
if err := csrlib.VerifyCSR(
ctx,
csr,
ca.maxNames,
&ca.keyPolicy,

View File

@ -15,7 +15,7 @@ import (
pkcs11key "github.com/letsencrypt/pkcs11key/v4"
"github.com/letsencrypt/boulder/ca"
"github.com/letsencrypt/boulder/ca/config"
ca_config "github.com/letsencrypt/boulder/ca/config"
caPB "github.com/letsencrypt/boulder/ca/proto"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
@ -155,9 +155,6 @@ func main() {
issuers, err := loadIssuers(c)
cmd.FailOnError(err, "Couldn't load issuers")
kp, err := goodkey.NewKeyPolicy(c.CA.WeakKeyFile, c.CA.BlockedKeyFile)
cmd.FailOnError(err, "Unable to create key policy")
tlsConfig, err := c.CA.TLS.Load()
cmd.FailOnError(err, "TLS config")
@ -168,6 +165,13 @@ func main() {
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sa := bgrpc.NewStorageAuthorityClient(sapb.NewStorageAuthorityClient(conn))
var blockedKeyFunc goodkey.BlockedKeyCheckFunc
if features.Enabled(features.BlockedKeyTable) {
blockedKeyFunc = sa.KeyBlocked
}
kp, err := goodkey.NewKeyPolicy(c.CA.WeakKeyFile, c.CA.BlockedKeyFile, blockedKeyFunc)
cmd.FailOnError(err, "Unable to create key policy")
var orphanQueue *goque.Queue
if c.CA.OrphanQueueDir != "" {
orphanQueue, err = goque.OpenQueue(c.CA.OrphanQueueDir)

View File

@ -204,7 +204,11 @@ func main() {
pendingAuthorizationLifetime = time.Duration(c.RA.PendingAuthorizationLifetimeDays) * 24 * time.Hour
}
kp, err := goodkey.NewKeyPolicy(c.RA.WeakKeyFile, c.RA.BlockedKeyFile)
var blockedKeyFunc goodkey.BlockedKeyCheckFunc
if features.Enabled(features.BlockedKeyTable) {
blockedKeyFunc = sac.KeyBlocked
}
kp, err := goodkey.NewKeyPolicy(c.RA.WeakKeyFile, c.RA.BlockedKeyFile, blockedKeyFunc)
cmd.FailOnError(err, "Unable to create key policy")
if c.RA.MaxNames == 0 {

View File

@ -123,10 +123,14 @@ func main() {
clk := cmd.Clock()
// don't load any weak keys, but do load blocked keys
kp, err := goodkey.NewKeyPolicy("", c.WFE.BlockedKeyFile)
cmd.FailOnError(err, "Unable to create key policy")
rac, sac, rns, npm := setupWFE(c, logger, stats, clk)
var blockedKeyFunc goodkey.BlockedKeyCheckFunc
if features.Enabled(features.BlockedKeyTable) {
blockedKeyFunc = sac.KeyBlocked
}
// don't load any weak keys, but do load blocked keys
kp, err := goodkey.NewKeyPolicy("", c.WFE.BlockedKeyFile, blockedKeyFunc)
cmd.FailOnError(err, "Unable to create key policy")
wfe, err := wfe.NewWebFrontEndImpl(stats, clk, kp, rns, npm, logger)
cmd.FailOnError(err, "Unable to create WFE")
wfe.RA = rac

View File

@ -298,10 +298,14 @@ func main() {
clk := cmd.Clock()
// don't load any weak keys, but do load blocked keys
kp, err := goodkey.NewKeyPolicy("", c.WFE.BlockedKeyFile)
cmd.FailOnError(err, "Unable to create key policy")
rac, sac, rns, npm := setupWFE(c, logger, stats, clk)
var blockedKeyFunc goodkey.BlockedKeyCheckFunc
if features.Enabled(features.BlockedKeyTable) {
blockedKeyFunc = sac.KeyBlocked
}
// don't load any weak keys, but do load blocked keys
kp, err := goodkey.NewKeyPolicy("", c.WFE.BlockedKeyFile, blockedKeyFunc)
cmd.FailOnError(err, "Unable to create key policy")
if c.WFE.StaleTimeout.Duration == 0 {
c.WFE.StaleTimeout.Duration = time.Minute * 10

View File

@ -136,6 +136,7 @@ type StorageGetter interface {
CountInvalidAuthorizations2(ctx context.Context, req *sapb.CountInvalidAuthorizationsRequest) (*sapb.Count, error)
GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest) (*sapb.Authorizations, error)
SerialExists(ctx context.Context, req *sapb.Serial) (*sapb.Exists, error)
KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error)
}
// StorageAdder are the Boulder SA's write/update methods
@ -155,6 +156,7 @@ type StorageAdder interface {
NewAuthorizations2(ctx context.Context, req *sapb.AddPendingAuthorizationsRequest) (*sapb.Authorization2IDs, error)
FinalizeAuthorization2(ctx context.Context, req *sapb.FinalizeAuthorizationRequest) error
DeactivateAuthorization2(ctx context.Context, req *sapb.AuthorizationID2) (*corepb.Empty, error)
AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error)
}
// StorageAuthority interface represents a simple key/value

View File

@ -1,6 +1,7 @@
package csr
import (
"context"
"crypto"
"crypto/x509"
"strings"
@ -44,13 +45,13 @@ var (
// VerifyCSR checks the validity of a x509.CertificateRequest. Before doing checks it normalizes
// the CSR which lowers the case of DNS names and subject CN, and if forceCNFromSAN is true it
// will hoist a DNS name into the CN if it is empty.
func VerifyCSR(csr *x509.CertificateRequest, maxNames int, keyPolicy *goodkey.KeyPolicy, pa core.PolicyAuthority, forceCNFromSAN bool, regID int64) error {
func VerifyCSR(ctx context.Context, csr *x509.CertificateRequest, maxNames int, keyPolicy *goodkey.KeyPolicy, pa core.PolicyAuthority, forceCNFromSAN bool, regID int64) error {
normalizeCSR(csr, forceCNFromSAN)
key, ok := csr.PublicKey.(crypto.PublicKey)
if !ok {
return invalidPubKey
}
if err := keyPolicy.GoodKey(key); err != nil {
if err := keyPolicy.GoodKey(ctx, key); err != nil {
return berrors.BadPublicKeyError("invalid public key in CSR: %s", err)
}
if !goodSignatureAlgorithms[csr.SignatureAlgorithm] {

View File

@ -1,6 +1,7 @@
package csr
import (
"context"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
@ -170,7 +171,7 @@ func TestVerifyCSR(t *testing.T) {
}
for _, c := range cases {
err := VerifyCSR(c.csr, c.maxNames, c.keyPolicy, c.pa, true, c.regID)
err := VerifyCSR(context.Background(), c.csr, c.maxNames, c.keyPolicy, c.pa, true, c.regID)
test.AssertDeepEquals(t, c.expectedError, err)
}
}

View File

@ -26,11 +26,12 @@ func _() {
_ = x[StripDefaultSchemePort-15]
_ = x[StoreIssuerInfo-16]
_ = x[StoreKeyHashes-17]
_ = x[BlockedKeyTable-18]
}
const _FeatureFlag_name = "unusedWriteIssuedNamesPrecertHeadNonceStatusOKRemoveWFE2AccountIDCheckRenewalFirstParallelCheckFailedValidationDeleteUnusedChallengesCAAValidationMethodsCAAAccountURIEnforceMultiVAMultiVAFullResultsMandatoryPOSTAsGETAllowV1RegistrationV1DisableNewValidationsPrecertificateRevocationStripDefaultSchemePortStoreIssuerInfoStoreKeyHashes"
const _FeatureFlag_name = "unusedWriteIssuedNamesPrecertHeadNonceStatusOKRemoveWFE2AccountIDCheckRenewalFirstParallelCheckFailedValidationDeleteUnusedChallengesCAAValidationMethodsCAAAccountURIEnforceMultiVAMultiVAFullResultsMandatoryPOSTAsGETAllowV1RegistrationV1DisableNewValidationsPrecertificateRevocationStripDefaultSchemePortStoreIssuerInfoStoreKeyHashesBlockedKeyTable"
var _FeatureFlag_index = [...]uint16{0, 6, 29, 46, 65, 82, 111, 133, 153, 166, 180, 198, 216, 235, 258, 282, 304, 319, 333}
var _FeatureFlag_index = [...]uint16{0, 6, 29, 46, 65, 82, 111, 133, 153, 166, 180, 198, 216, 235, 258, 282, 304, 319, 333, 348}
func (i FeatureFlag) String() string {
if i < 0 || i >= FeatureFlag(len(_FeatureFlag_index)-1) {

View File

@ -49,6 +49,9 @@ const (
StoreIssuerInfo
// StoreKeyHashes enables storage of SPKI hashes associated with certificates.
StoreKeyHashes
// BlockedKeyTable enables storage, and checking, of the blockedKeys table in addition
// to the blocked key list
BlockedKeyTable
)
// List of features and their default value, protected by fMu
@ -71,6 +74,7 @@ var features = map[FeatureFlag]bool{
StoreIssuerInfo: false,
WriteIssuedNamesPrecert: false,
StoreKeyHashes: false,
BlockedKeyTable: false,
}
var fMu = new(sync.RWMutex)

View File

@ -1,6 +1,7 @@
package goodkey
import (
"context"
"crypto"
"io/ioutil"
"os"
@ -85,7 +86,7 @@ func TestBlockedKeys(t *testing.T) {
// All of the test keys should not be considered blocked
for _, k := range blockedKeys {
err := testingPolicy.GoodKey(k)
err := testingPolicy.GoodKey(context.Background(), k)
test.AssertNotError(t, err, "test key was blocked by key policy without block list")
}
@ -95,7 +96,7 @@ func TestBlockedKeys(t *testing.T) {
// Now all of the test keys should be considered blocked, and with the correct
// type of error.
for _, k := range blockedKeys {
err := testingPolicy.GoodKey(k)
err := testingPolicy.GoodKey(context.Background(), k)
test.AssertError(t, err, "test key was not blocked by key policy with block list")
test.Assert(t, berrors.Is(err, berrors.BadPublicKey), "err was not BadPublicKey error")
}

View File

@ -1,6 +1,7 @@
package goodkey
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
@ -8,7 +9,10 @@ import (
"math/big"
"sync"
"github.com/letsencrypt/boulder/core"
berrors "github.com/letsencrypt/boulder/errors"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/titanous/rocacheck"
)
@ -34,6 +38,11 @@ var (
smallPrimes []*big.Int
)
// BlockedKeyCheckFunc is used to pass in the sa.BlockedKey method to KeyPolicy,
// rather than storing a full sa.SQLStorageAuthority. This makes testing
// significantly simpler.
type BlockedKeyCheckFunc func(context.Context, *sapb.KeyBlockedRequest) (*sapb.Exists, error)
// KeyPolicy determines which types of key may be used with various boulder
// operations.
type KeyPolicy struct {
@ -42,6 +51,7 @@ type KeyPolicy struct {
AllowECDSANISTP384 bool // Whether ECDSA NISTP384 keys should be allowed.
weakRSAList *WeakRSAKeys
blockedList *blockedKeys
dbCheck BlockedKeyCheckFunc
}
// NewKeyPolicy returns a KeyPolicy that allows RSA, ECDSA256 and ECDSA384.
@ -51,11 +61,12 @@ type KeyPolicy struct {
// containing Base64 encoded SHA256 hashes of pkix subject public keys that
// should be blocked. If this argument is empty then no blocked key checking is
// performed.
func NewKeyPolicy(weakKeyFile, blockedKeyFile string) (KeyPolicy, error) {
func NewKeyPolicy(weakKeyFile, blockedKeyFile string, bkc BlockedKeyCheckFunc) (KeyPolicy, error) {
kp := KeyPolicy{
AllowRSA: true,
AllowECDSANISTP256: true,
AllowECDSANISTP384: true,
dbCheck: bkc,
}
if weakKeyFile != "" {
keyList, err := LoadWeakRSASuffixes(weakKeyFile)
@ -79,7 +90,7 @@ func NewKeyPolicy(weakKeyFile, blockedKeyFile string) (KeyPolicy, error) {
// strength and algorithm checking. GoodKey only supports pointers: *rsa.PublicKey
// and *ecdsa.PublicKey. It will reject non-pointer types.
// TODO: Support JSONWebKeys once go-jose migration is done.
func (policy *KeyPolicy) GoodKey(key crypto.PublicKey) error {
func (policy *KeyPolicy) GoodKey(ctx context.Context, key crypto.PublicKey) error {
// If there is a blocked list configured then check if the public key is one
// that has been administratively blocked.
if policy.blockedList != nil {
@ -89,6 +100,19 @@ func (policy *KeyPolicy) GoodKey(key crypto.PublicKey) error {
return berrors.BadPublicKeyError("public key is forbidden")
}
}
if policy.dbCheck != nil {
digest, err := core.KeyDigest(key)
if err != nil {
return err
}
exists, err := policy.dbCheck(ctx, &sapb.KeyBlockedRequest{KeyHash: digest[:]})
if err != nil {
return err
}
if *exists.Exists {
return berrors.BadPublicKeyError("public key is forbidden")
}
}
switch t := key.(type) {
case *rsa.PublicKey:
return policy.goodKeyRSA(t)

View File

@ -1,6 +1,7 @@
package goodkey
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
@ -9,6 +10,8 @@ import (
"math/big"
"testing"
berrors "github.com/letsencrypt/boulder/errors"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/letsencrypt/boulder/test"
)
@ -20,13 +23,13 @@ var testingPolicy = &KeyPolicy{
func TestUnknownKeyType(t *testing.T) {
notAKey := struct{}{}
err := testingPolicy.GoodKey(notAKey)
err := testingPolicy.GoodKey(context.Background(), notAKey)
test.AssertError(t, err, "Should have rejected a key of unknown type")
test.AssertEquals(t, err.Error(), "unknown key type struct {}")
}
func TestNilKey(t *testing.T) {
err := testingPolicy.GoodKey(nil)
err := testingPolicy.GoodKey(context.Background(), nil)
test.AssertError(t, err, "Should have rejected a nil key")
test.AssertEquals(t, err.Error(), "unknown key type <nil>")
}
@ -41,7 +44,7 @@ func TestSmallModulus(t *testing.T) {
if !ok {
t.Errorf("error parsing pubkey modulus")
}
err := testingPolicy.GoodKey(&pubKey)
err := testingPolicy.GoodKey(context.Background(), &pubKey)
test.AssertError(t, err, "Should have rejected too-short key")
test.AssertEquals(t, err.Error(), "key too small: 2040")
}
@ -56,7 +59,7 @@ func TestLargeModulus(t *testing.T) {
if !ok {
t.Errorf("error parsing pubkey modulus")
}
err := testingPolicy.GoodKey(&pubKey)
err := testingPolicy.GoodKey(context.Background(), &pubKey)
test.AssertError(t, err, "Should have rejected too-long key")
test.AssertEquals(t, err.Error(), "key too large: 4097 > 4096")
}
@ -67,7 +70,7 @@ func TestModulusModulo8(t *testing.T) {
N: bigOne.Lsh(bigOne, 2048),
E: 5,
}
err := testingPolicy.GoodKey(&key)
err := testingPolicy.GoodKey(context.Background(), &key)
test.AssertError(t, err, "Should have rejected modulus with length not divisible by 8")
test.AssertEquals(t, err.Error(), "key length wasn't a multiple of 8: 2049")
}
@ -80,7 +83,7 @@ func TestNonStandardExp(t *testing.T) {
N: evenMod,
E: (1 << 16),
}
err := testingPolicy.GoodKey(&key)
err := testingPolicy.GoodKey(context.Background(), &key)
test.AssertError(t, err, "Should have rejected non-standard exponent")
test.AssertEquals(t, err.Error(), "key exponent must be 65537")
}
@ -91,7 +94,7 @@ func TestEvenModulus(t *testing.T) {
N: evenMod,
E: (1 << 16) + 1,
}
err := testingPolicy.GoodKey(&key)
err := testingPolicy.GoodKey(context.Background(), &key)
test.AssertError(t, err, "Should have rejected even modulus")
test.AssertEquals(t, err.Error(), "key divisible by small prime")
}
@ -101,7 +104,7 @@ func TestModulusDivisibleBySmallPrime(t *testing.T) {
N: mod2048,
E: (1 << 16) + 1,
}
err := testingPolicy.GoodKey(&key)
err := testingPolicy.GoodKey(context.Background(), &key)
test.AssertError(t, err, "Should have rejected modulus divisible by 3")
test.AssertEquals(t, err.Error(), "key divisible by small prime")
}
@ -115,7 +118,7 @@ func TestROCA(t *testing.T) {
N: n,
E: 65537,
}
err := testingPolicy.GoodKey(&key)
err := testingPolicy.GoodKey(context.Background(), &key)
test.AssertError(t, err, "Should have rejected ROCA-weak key")
test.AssertEquals(t, err.Error(), "key generated by vulnerable Infineon-based hardware")
}
@ -123,14 +126,14 @@ func TestROCA(t *testing.T) {
func TestGoodKey(t *testing.T) {
private, err := rsa.GenerateKey(rand.Reader, 2048)
test.AssertNotError(t, err, "Error generating key")
test.AssertNotError(t, testingPolicy.GoodKey(&private.PublicKey), "Should have accepted good key")
test.AssertNotError(t, testingPolicy.GoodKey(context.Background(), &private.PublicKey), "Should have accepted good key")
}
func TestECDSABadCurve(t *testing.T) {
for _, curve := range invalidCurves {
private, err := ecdsa.GenerateKey(curve, rand.Reader)
test.AssertNotError(t, err, "Error generating key")
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should have rejected key with unsupported curve")
test.AssertEquals(t, err.Error(), fmt.Sprintf("ECDSA curve %s not allowed", curve.Params().Name))
}
@ -150,7 +153,7 @@ func TestECDSAGoodKey(t *testing.T) {
for _, curve := range validCurves {
private, err := ecdsa.GenerateKey(curve, rand.Reader)
test.AssertNotError(t, err, "Error generating key")
test.AssertNotError(t, testingPolicy.GoodKey(&private.PublicKey), "Should have accepted good key")
test.AssertNotError(t, testingPolicy.GoodKey(context.Background(), &private.PublicKey), "Should have accepted good key")
}
}
@ -161,7 +164,7 @@ func TestECDSANotOnCurveX(t *testing.T) {
test.AssertNotError(t, err, "Error generating key")
private.X.Add(private.X, big.NewInt(1))
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key not on the curve")
test.AssertEquals(t, err.Error(), "key point is not on the curve")
}
@ -175,7 +178,7 @@ func TestECDSANotOnCurveY(t *testing.T) {
// Change the public key so that it is no longer on the curve.
private.Y.Add(private.Y, big.NewInt(1))
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key not on the curve")
test.AssertEquals(t, err.Error(), "key point is not on the curve")
}
@ -188,14 +191,14 @@ func TestECDSANegative(t *testing.T) {
test.AssertNotError(t, err, "Error generating key")
private.X.Neg(private.X)
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key with negative X")
test.AssertEquals(t, err.Error(), "key x, y must not be negative")
// Check that negative Y is not accepted.
private.X.Neg(private.X)
private.Y.Neg(private.Y)
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key with negative Y")
test.AssertEquals(t, err.Error(), "key x, y must not be negative")
}
@ -208,7 +211,7 @@ func TestECDSAXOutsideField(t *testing.T) {
test.AssertNotError(t, err, "Error generating key")
private.X.Mul(private.X, private.Curve.Params().P)
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key with a X > p-1")
test.AssertEquals(t, err.Error(), "key x, y must not exceed P-1")
}
@ -221,7 +224,7 @@ func TestECDSAYOutsideField(t *testing.T) {
test.AssertNotError(t, err, "Error generating key")
private.X.Mul(private.Y, private.Curve.Params().P)
err = testingPolicy.GoodKey(&private.PublicKey)
err = testingPolicy.GoodKey(context.Background(), &private.PublicKey)
test.AssertError(t, err, "Should not have accepted key with a Y > p-1")
test.AssertEquals(t, err.Error(), "key x, y must not exceed P-1")
}
@ -236,7 +239,7 @@ func TestECDSAIdentity(t *testing.T) {
Y: big.NewInt(0),
}
err := testingPolicy.GoodKey(&public)
err := testingPolicy.GoodKey(context.Background(), &public)
test.AssertError(t, err, "Should not have accepted key with point at infinity")
test.AssertEquals(t, err.Error(), "key x, y must not be the point at infinity")
}
@ -245,5 +248,25 @@ func TestECDSAIdentity(t *testing.T) {
func TestNonRefKey(t *testing.T) {
private, err := rsa.GenerateKey(rand.Reader, 2048)
test.AssertNotError(t, err, "Error generating key")
test.AssertError(t, testingPolicy.GoodKey(private.PublicKey), "Accepted non-reference key")
test.AssertError(t, testingPolicy.GoodKey(context.Background(), private.PublicKey), "Accepted non-reference key")
}
func TestDBBlacklist(t *testing.T) {
exists := false
testCheck := func(context.Context, *sapb.KeyBlockedRequest) (*sapb.Exists, error) {
return &sapb.Exists{Exists: &exists}, nil
}
policy, err := NewKeyPolicy("", "", testCheck)
test.AssertNotError(t, err, "NewKeyPolicy failed")
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "ecdsa.GenerateKey failed")
err = policy.GoodKey(context.Background(), k.Public())
test.AssertNotError(t, err, "GoodKey failed with a non-blocked key")
exists = true
err = policy.GoodKey(context.Background(), k.Public())
test.AssertError(t, err, "GoodKey didn't fail with a blocked key")
test.Assert(t, berrors.Is(err, berrors.BadPublicKey), "returned error is wrong type")
test.AssertEquals(t, err.Error(), "public key is forbidden")
}

View File

@ -500,6 +500,16 @@ func (sas StorageAuthorityClientWrapper) SerialExists(ctx context.Context, req *
return res, nil
}
func (sac StorageAuthorityClientWrapper) AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error) {
// All return checking is done at the call site
return sac.inner.AddBlockedKey(ctx, req)
}
func (sac StorageAuthorityClientWrapper) KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error) {
// All return checking is done at the call site
return sac.inner.KeyBlocked(ctx, req)
}
// StorageAuthorityServerWrapper is the gRPC version of a core.ServerAuthority server
type StorageAuthorityServerWrapper struct {
// TODO(#3119): Don't use core.StorageAuthority
@ -916,3 +926,13 @@ func (sas StorageAuthorityServerWrapper) SerialExists(ctx context.Context, req *
}
return sas.inner.SerialExists(ctx, req)
}
func (sas StorageAuthorityServerWrapper) AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error) {
// All request checking is done in the method
return sas.inner.AddBlockedKey(ctx, req)
}
func (sas StorageAuthorityServerWrapper) KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error) {
// All request checking is done in the method
return sas.inner.KeyBlocked(ctx, req)
}

View File

@ -700,6 +700,17 @@ func (sa *StorageAuthority) RevokeCertificate(ctx context.Context, req *sapb.Rev
return nil
}
// AddBlockedKey is a mock
func (sa *StorageAuthority) AddBlockedKey(context.Context, *sapb.AddBlockedKeyRequest) (*corepb.Empty, error) {
return &corepb.Empty{}, nil
}
// KeyBlocked is a mock
func (sa *StorageAuthority) KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error) {
exists := false
return &sapb.Exists{Exists: &exists}, nil
}
// Publisher is a mock
type Publisher struct {
// empty

View File

@ -320,7 +320,7 @@ func (ra *RegistrationAuthorityImpl) checkRegistrationLimits(ctx context.Context
// NewRegistration constructs a new Registration from a request.
func (ra *RegistrationAuthorityImpl) NewRegistration(ctx context.Context, init core.Registration) (core.Registration, error) {
if err := ra.keyPolicy.GoodKey(init.Key.Key); err != nil {
if err := ra.keyPolicy.GoodKey(ctx, init.Key.Key); err != nil {
return core.Registration{}, berrors.MalformedError("invalid public key: %s", err.Error())
}
if err := ra.checkRegistrationLimits(ctx, init.InitialIP); err != nil {
@ -985,7 +985,7 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
return nil, err
}
if err := csrlib.VerifyCSR(csrOb, ra.maxNames, &ra.keyPolicy, ra.PA, ra.forceCNFromSAN, *req.Order.RegistrationID); err != nil {
if err := csrlib.VerifyCSR(ctx, csrOb, ra.maxNames, &ra.keyPolicy, ra.PA, ra.forceCNFromSAN, *req.Order.RegistrationID); err != nil {
// VerifyCSR returns berror instances that can be passed through as-is
// without wrapping.
return nil, err
@ -1076,7 +1076,7 @@ func (ra *RegistrationAuthorityImpl) FinalizeOrder(ctx context.Context, req *rap
// NewCertificate requests the issuance of a certificate.
func (ra *RegistrationAuthorityImpl) NewCertificate(ctx context.Context, req core.CertificateRequest, regID int64) (core.Certificate, error) {
// Verify the CSR
if err := csrlib.VerifyCSR(req.CSR, ra.maxNames, &ra.keyPolicy, ra.PA, ra.forceCNFromSAN, regID); err != nil {
if err := csrlib.VerifyCSR(ctx, req.CSR, ra.maxNames, &ra.keyPolicy, ra.PA, ra.forceCNFromSAN, regID); err != nil {
return core.Certificate{}, berrors.MalformedError(err.Error())
}
// NewCertificate provides an order ID of 0, indicating this is a classic ACME
@ -1687,10 +1687,10 @@ func revokeEvent(state, serial, cn string, names []string, revocationCode revoca
// revokeCertificate generates a revoked OCSP response for the given certificate, stores
// the revocation information, and purges OCSP request URLs from Akamai.
func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert x509.Certificate, code revocation.Reason) error {
func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert x509.Certificate, code revocation.Reason, source string, comment string) error {
status := string(core.OCSPStatusRevoked)
reason := int32(code)
revokedAt := time.Now().UnixNano()
revokedAt := ra.clk.Now().UnixNano()
ocspResponse, err := ra.CA.GenerateOCSP(ctx, &caPB.GenerateOCSPRequest{
CertDER: cert.Raw,
Status: &status,
@ -1713,6 +1713,23 @@ func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert
if err != nil {
return err
}
if features.Enabled(features.BlockedKeyTable) && reason == revocation.KeyCompromise {
digest, err := core.KeyDigest(cert.PublicKey)
if err != nil {
return err
}
req := &sapb.AddBlockedKeyRequest{
KeyHash: digest[:],
Added: &revokedAt,
Source: &source,
}
if comment != "" {
req.Comment = &comment
}
if _, err = ra.SA.AddBlockedKey(ctx, req); err != nil {
return err
}
}
purgeURLs, err := akamai.GeneratePurgeURLs(cert.Raw, ra.issuer)
if err != nil {
return err
@ -1728,7 +1745,7 @@ func (ra *RegistrationAuthorityImpl) revokeCertificate(ctx context.Context, cert
// RevokeCertificateWithReg terminates trust in the certificate provided.
func (ra *RegistrationAuthorityImpl) RevokeCertificateWithReg(ctx context.Context, cert x509.Certificate, revocationCode revocation.Reason, regID int64) error {
serialString := core.SerialToString(cert.SerialNumber)
err := ra.revokeCertificate(ctx, cert, revocationCode)
err := ra.revokeCertificate(ctx, cert, revocationCode, "API", "")
state := "Failure"
defer func() {
@ -1758,7 +1775,9 @@ func (ra *RegistrationAuthorityImpl) RevokeCertificateWithReg(ctx context.Contex
// called from the admin-revoker tool.
func (ra *RegistrationAuthorityImpl) AdministrativelyRevokeCertificate(ctx context.Context, cert x509.Certificate, revocationCode revocation.Reason, user string) error {
serialString := core.SerialToString(cert.SerialNumber)
err := ra.revokeCertificate(ctx, cert, revocationCode)
// TODO(#4774): allow setting the comment via the RPC, format should be:
// "revoked by %s: %s", user, comment
err := ra.revokeCertificate(ctx, cert, revocationCode, "admin-revoker", fmt.Sprintf("revoked by %s", user))
state := "Failure"
defer func() {

View File

@ -1,6 +1,7 @@
package ra
import (
"bytes"
"context"
"crypto/ecdsa"
"crypto/elliptic"
@ -28,6 +29,7 @@ import (
ctx509 "github.com/google/certificate-transparency-go/x509"
ctpkix "github.com/google/certificate-transparency-go/x509/pkix"
"github.com/jmhodges/clock"
akamaipb "github.com/letsencrypt/boulder/akamai/proto"
capb "github.com/letsencrypt/boulder/ca/proto"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
@ -47,6 +49,7 @@ import (
pubpb "github.com/letsencrypt/boulder/publisher/proto"
rapb "github.com/letsencrypt/boulder/ra/proto"
"github.com/letsencrypt/boulder/ratelimit"
"github.com/letsencrypt/boulder/revocation"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
"github.com/letsencrypt/boulder/test"
@ -3809,3 +3812,74 @@ xGUhoOJp0T++nz6R3TX7Rwk7KmG6xX3vWr/MFu5A3c8fvkqj987Vti5BeBezCXfs
rA==
-----END CERTIFICATE-----
`)
type mockSABlockedKey struct {
mocks.StorageAuthority
added *sapb.AddBlockedKeyRequest
}
func (msabk *mockSABlockedKey) AddBlockedKey(_ context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error) {
msabk.added = req
return &corepb.Empty{}, nil
}
type mockCAOCSP struct {
mocks.MockCA
}
func (mcao *mockCAOCSP) GenerateOCSP(context.Context, *capb.GenerateOCSPRequest) (*capb.OCSPResponse, error) {
return &capb.OCSPResponse{Response: []byte{1, 2, 3}}, nil
}
type mockPurger struct{}
func (mp *mockPurger) Purge(context.Context, *akamaipb.PurgeRequest, ...grpc.CallOption) (*corepb.Empty, error) {
return &corepb.Empty{}, nil
}
func TestRevocationAddBlockedKey(t *testing.T) {
_, _, ra, _, cleanUp := initAuthorities(t)
defer cleanUp()
err := features.Set(map[string]bool{"BlockedKeyTable": true})
test.AssertNotError(t, err, "features.Set failed")
defer features.Reset()
mockSA := mockSABlockedKey{}
ra.SA = &mockSA
ra.CA = &mockCAOCSP{}
ra.purger = &mockPurger{}
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "ecdsa.GenerateKey failed")
digest, err := core.KeyDigest(k.Public())
test.AssertNotError(t, err, "core.KeyDigest failed")
template := x509.Certificate{PublicKey: k, SerialNumber: big.NewInt(257)}
der, err := x509.CreateCertificate(rand.Reader, &template, &template, k.Public(), k)
test.AssertNotError(t, err, "x509.CreateCertificate failed")
cert, err := x509.ParseCertificate(der)
test.AssertNotError(t, err, "x509.ParseCertificate failed")
ra.issuer = cert
err = ra.RevokeCertificateWithReg(context.Background(), *cert, revocation.Unspecified, 0)
test.AssertNotError(t, err, "RevokeCertificateWithReg failed")
test.Assert(t, mockSA.added == nil, "blocked key was added when reason was not keyCompromise")
err = ra.RevokeCertificateWithReg(context.Background(), *cert, revocation.KeyCompromise, 0)
test.AssertNotError(t, err, "RevokeCertificateWithReg failed")
test.Assert(t, mockSA.added != nil, "blocked key was not added when reason was keyCompromise")
test.Assert(t, bytes.Equal(digest[:], mockSA.added.KeyHash), "key hash mismatch")
test.AssertEquals(t, *mockSA.added.Source, "API")
test.Assert(t, mockSA.added.Comment == nil, "Comment is not nil")
mockSA.added = nil
err = ra.AdministrativelyRevokeCertificate(context.Background(), *cert, revocation.KeyCompromise, "root")
test.AssertNotError(t, err, "AdministrativelyRevokeCertificate failed")
test.Assert(t, mockSA.added != nil, "blocked key was not added when reason was keyCompromise")
test.Assert(t, bytes.Equal(digest[:], mockSA.added.KeyHash), "key hash mismatch")
test.AssertEquals(t, *mockSA.added.Source, "admin-revoker")
test.Assert(t, mockSA.added.Comment != nil, "Comment is nil")
test.AssertEquals(t, *mockSA.added.Comment, "revoked by root")
}

View File

@ -0,0 +1,17 @@
-- +goose Up
-- SQL in section 'Up' is executed when this migration is applied
CREATE TABLE `blockedKeys` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`keyHash` binary(32) NOT NULL UNIQUE,
`added` datetime NOT NULL,
`source` tinyint NOT NULL,
`comment` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- +goose Down
-- SQL section 'Down' is executed when this migration is rolled back
DROP TABLE `blockedKeys`;

View File

@ -140,4 +140,5 @@ func initTables(dbMap *gorp.DbMap) {
dbMap.AddTableWithName(recordedSerialModel{}, "serials").SetKeys(true, "ID")
dbMap.AddTableWithName(precertificateModel{}, "precertificates").SetKeys(true, "ID")
dbMap.AddTableWithName(keyHashModel{}, "keyHashToSerial").SetKeys(true, "ID")
dbMap.AddTableWithName(blockedKeyModel{}, "blockedKeys").SetKeys(true, "ID")
}

View File

@ -617,3 +617,16 @@ type keyHashModel struct {
CertNotAfter time.Time
CertSerial string
}
var stringToSourceInt = map[string]int{
"API": 1,
"admin-revoker": 2,
}
type blockedKeyModel struct {
ID int64
KeyHash []byte
Added time.Time
Source int
Comment *string
}

View File

@ -1804,6 +1804,108 @@ func (m *FinalizeAuthorizationRequest) GetValidationError() *proto1.ProblemDetai
return nil
}
type AddBlockedKeyRequest struct {
KeyHash []byte `protobuf:"bytes,1,opt,name=keyHash" json:"keyHash,omitempty"`
Added *int64 `protobuf:"varint,2,opt,name=added" json:"added,omitempty"`
Source *string `protobuf:"bytes,3,opt,name=source" json:"source,omitempty"`
Comment *string `protobuf:"bytes,4,opt,name=comment" json:"comment,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *AddBlockedKeyRequest) Reset() { *m = AddBlockedKeyRequest{} }
func (m *AddBlockedKeyRequest) String() string { return proto.CompactTextString(m) }
func (*AddBlockedKeyRequest) ProtoMessage() {}
func (*AddBlockedKeyRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_099fb35e782a48a6, []int{33}
}
func (m *AddBlockedKeyRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_AddBlockedKeyRequest.Unmarshal(m, b)
}
func (m *AddBlockedKeyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_AddBlockedKeyRequest.Marshal(b, m, deterministic)
}
func (m *AddBlockedKeyRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_AddBlockedKeyRequest.Merge(m, src)
}
func (m *AddBlockedKeyRequest) XXX_Size() int {
return xxx_messageInfo_AddBlockedKeyRequest.Size(m)
}
func (m *AddBlockedKeyRequest) XXX_DiscardUnknown() {
xxx_messageInfo_AddBlockedKeyRequest.DiscardUnknown(m)
}
var xxx_messageInfo_AddBlockedKeyRequest proto.InternalMessageInfo
func (m *AddBlockedKeyRequest) GetKeyHash() []byte {
if m != nil {
return m.KeyHash
}
return nil
}
func (m *AddBlockedKeyRequest) GetAdded() int64 {
if m != nil && m.Added != nil {
return *m.Added
}
return 0
}
func (m *AddBlockedKeyRequest) GetSource() string {
if m != nil && m.Source != nil {
return *m.Source
}
return ""
}
func (m *AddBlockedKeyRequest) GetComment() string {
if m != nil && m.Comment != nil {
return *m.Comment
}
return ""
}
type KeyBlockedRequest struct {
KeyHash []byte `protobuf:"bytes,1,opt,name=keyHash" json:"keyHash,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *KeyBlockedRequest) Reset() { *m = KeyBlockedRequest{} }
func (m *KeyBlockedRequest) String() string { return proto.CompactTextString(m) }
func (*KeyBlockedRequest) ProtoMessage() {}
func (*KeyBlockedRequest) Descriptor() ([]byte, []int) {
return fileDescriptor_099fb35e782a48a6, []int{34}
}
func (m *KeyBlockedRequest) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_KeyBlockedRequest.Unmarshal(m, b)
}
func (m *KeyBlockedRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_KeyBlockedRequest.Marshal(b, m, deterministic)
}
func (m *KeyBlockedRequest) XXX_Merge(src proto.Message) {
xxx_messageInfo_KeyBlockedRequest.Merge(m, src)
}
func (m *KeyBlockedRequest) XXX_Size() int {
return xxx_messageInfo_KeyBlockedRequest.Size(m)
}
func (m *KeyBlockedRequest) XXX_DiscardUnknown() {
xxx_messageInfo_KeyBlockedRequest.DiscardUnknown(m)
}
var xxx_messageInfo_KeyBlockedRequest proto.InternalMessageInfo
func (m *KeyBlockedRequest) GetKeyHash() []byte {
if m != nil {
return m.KeyHash
}
return nil
}
func init() {
proto.RegisterType((*RegistrationID)(nil), "sa.RegistrationID")
proto.RegisterType((*JSONWebKey)(nil), "sa.JSONWebKey")
@ -1841,121 +1943,129 @@ func init() {
proto.RegisterType((*Authorization2IDs)(nil), "sa.Authorization2IDs")
proto.RegisterType((*RevokeCertificateRequest)(nil), "sa.RevokeCertificateRequest")
proto.RegisterType((*FinalizeAuthorizationRequest)(nil), "sa.FinalizeAuthorizationRequest")
proto.RegisterType((*AddBlockedKeyRequest)(nil), "sa.AddBlockedKeyRequest")
proto.RegisterType((*KeyBlockedRequest)(nil), "sa.KeyBlockedRequest")
}
func init() { proto.RegisterFile("sa/proto/sa.proto", fileDescriptor_099fb35e782a48a6) }
var fileDescriptor_099fb35e782a48a6 = []byte{
// 1739 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xdd, 0x6e, 0xdb, 0xc8,
0x15, 0xd6, 0x8f, 0x65, 0x4b, 0xc7, 0x7f, 0xd2, 0xc4, 0x56, 0xb9, 0x8a, 0x9d, 0xc8, 0xb3, 0xd9,
0xc0, 0x8b, 0x02, 0x5e, 0x97, 0x5d, 0xec, 0x16, 0x70, 0x9b, 0xc4, 0x8e, 0x1c, 0xc7, 0x69, 0x62,
0x2b, 0x54, 0xe3, 0x16, 0x45, 0x6f, 0x18, 0x71, 0xa2, 0xb0, 0x91, 0x49, 0x65, 0x66, 0x64, 0x47,
0xbe, 0x2e, 0xd0, 0x3e, 0x41, 0x51, 0xa0, 0x37, 0x7d, 0x8e, 0xbe, 0x44, 0x5f, 0xa9, 0x98, 0xc3,
0x21, 0x45, 0x52, 0xa4, 0x5c, 0xa3, 0x45, 0xef, 0xe6, 0x9c, 0x39, 0x7f, 0x33, 0x73, 0x7e, 0x3e,
0x12, 0x1a, 0xc2, 0xfe, 0x6e, 0xc4, 0x7d, 0xe9, 0x7f, 0x27, 0xec, 0x3d, 0x5c, 0x90, 0x92, 0xb0,
0x5b, 0x9b, 0x7d, 0x9f, 0x33, 0xbd, 0xa1, 0x96, 0xc1, 0x16, 0x6d, 0xc3, 0x9a, 0xc5, 0x06, 0xae,
0x90, 0xdc, 0x96, 0xae, 0xef, 0x9d, 0x76, 0xc8, 0x1a, 0x94, 0x5c, 0xc7, 0x28, 0xb6, 0x8b, 0xbb,
0x65, 0xab, 0xe4, 0x3a, 0xf4, 0x01, 0xc0, 0xab, 0xde, 0xf9, 0xd9, 0x6f, 0xd9, 0xfb, 0x5f, 0xb3,
0x09, 0xa9, 0x43, 0xf9, 0x8f, 0xd7, 0x9f, 0x70, 0x7b, 0xc5, 0x52, 0x4b, 0xba, 0x03, 0xeb, 0x87,
0x63, 0xf9, 0xd1, 0xe7, 0xee, 0xcd, 0xac, 0x89, 0x1a, 0x9a, 0xf8, 0x67, 0x11, 0x1e, 0x9c, 0x30,
0xd9, 0x65, 0x9e, 0xe3, 0x7a, 0x83, 0x84, 0xb4, 0xc5, 0x3e, 0x8f, 0x99, 0x90, 0xe4, 0x31, 0xac,
0xf1, 0x44, 0x1c, 0x3a, 0x82, 0x14, 0x57, 0xc9, 0xb9, 0x0e, 0xf3, 0xa4, 0xfb, 0xc1, 0x65, 0xfc,
0x37, 0x93, 0x11, 0x33, 0x4a, 0xe8, 0x26, 0xc5, 0x25, 0xbb, 0xb0, 0x3e, 0xe5, 0x5c, 0xd8, 0xc3,
0x31, 0x33, 0xca, 0x28, 0x98, 0x66, 0x93, 0x07, 0x00, 0x57, 0xf6, 0xd0, 0x75, 0xde, 0x79, 0xd2,
0x1d, 0x1a, 0x0b, 0xe8, 0x35, 0xc6, 0xa1, 0x02, 0xb6, 0x4f, 0x98, 0xbc, 0x50, 0x8c, 0x44, 0xe4,
0xe2, 0xae, 0xa1, 0x1b, 0xb0, 0xe4, 0xf8, 0x97, 0xb6, 0xeb, 0x09, 0xa3, 0xd4, 0x2e, 0xef, 0xd6,
0xac, 0x90, 0x54, 0x97, 0xea, 0xf9, 0xd7, 0x18, 0x60, 0xd9, 0x52, 0x4b, 0xfa, 0x8f, 0x22, 0xdc,
0xcb, 0x70, 0x49, 0x7e, 0x01, 0x15, 0x0c, 0xcd, 0x28, 0xb6, 0xcb, 0xbb, 0xcb, 0x26, 0xdd, 0x13,
0xf6, 0x5e, 0x86, 0xdc, 0xde, 0x1b, 0x7b, 0x74, 0x3c, 0x64, 0x97, 0xcc, 0x93, 0x56, 0xa0, 0xd0,
0x3a, 0x07, 0x98, 0x32, 0x49, 0x13, 0x16, 0x03, 0xe7, 0xfa, 0x95, 0x34, 0x45, 0xbe, 0x85, 0x8a,
0x3d, 0x96, 0x1f, 0x6f, 0xf0, 0x56, 0x97, 0xcd, 0x7b, 0x7b, 0x98, 0x2a, 0xc9, 0x17, 0x0b, 0x24,
0xe8, 0xbf, 0x4a, 0xd0, 0x78, 0xce, 0xb8, 0xba, 0xca, 0xbe, 0x2d, 0x59, 0x4f, 0xda, 0x72, 0x2c,
0x94, 0x61, 0xc1, 0xb8, 0x6b, 0x0f, 0x43, 0xc3, 0x01, 0x85, 0x7c, 0x94, 0xd0, 0xcf, 0xa0, 0x29,
0xf5, 0x4e, 0x7e, 0x5f, 0x8c, 0x5e, 0xdb, 0x42, 0xbe, 0x1b, 0x39, 0xb6, 0x64, 0x8e, 0x7e, 0x82,
0x34, 0x9b, 0xb4, 0x61, 0x99, 0xb3, 0x2b, 0xff, 0x13, 0x73, 0x3a, 0xb6, 0x64, 0x46, 0x05, 0xa5,
0xe2, 0x2c, 0xf2, 0x08, 0x56, 0x35, 0x69, 0x31, 0x5b, 0xf8, 0x9e, 0xb1, 0x88, 0x32, 0x49, 0x26,
0xf9, 0x1e, 0x36, 0x87, 0xb6, 0x90, 0xc7, 0x5f, 0x46, 0x6e, 0xf0, 0x34, 0x67, 0xf6, 0xa0, 0xc7,
0x3c, 0x69, 0x2c, 0xa1, 0x74, 0xf6, 0x26, 0xa1, 0xb0, 0xa2, 0x02, 0xb2, 0x98, 0x18, 0xf9, 0x9e,
0x60, 0x46, 0x15, 0x0b, 0x20, 0xc1, 0x23, 0x2d, 0xa8, 0x7a, 0xbe, 0x3c, 0xfc, 0x20, 0x19, 0x37,
0x6a, 0x68, 0x2c, 0xa2, 0xc9, 0x16, 0xd4, 0x5c, 0x81, 0x66, 0x99, 0x63, 0x40, 0xbb, 0xb8, 0x5b,
0xb5, 0xa6, 0x8c, 0x57, 0x0b, 0xd5, 0x52, 0xbd, 0x4c, 0xdb, 0xb0, 0xd8, 0x9b, 0xde, 0x56, 0xc6,
0x2d, 0xd2, 0x03, 0xa8, 0x58, 0xb6, 0x37, 0x40, 0x57, 0xcc, 0xe6, 0x43, 0x97, 0x09, 0xa9, 0xb3,
0x2d, 0xa2, 0x95, 0xf2, 0xd0, 0x96, 0x6a, 0xa7, 0x84, 0x3b, 0x9a, 0xa2, 0xdb, 0x50, 0x79, 0xee,
0x8f, 0x3d, 0x49, 0x36, 0xa0, 0xd2, 0x57, 0x0b, 0xad, 0x19, 0x10, 0xf4, 0x77, 0xf0, 0x10, 0xb7,
0x63, 0x6f, 0x2a, 0x8e, 0x26, 0x67, 0xf6, 0x25, 0x8b, 0x32, 0xfd, 0x21, 0x54, 0xb8, 0x72, 0x8f,
0x8a, 0xcb, 0x66, 0x4d, 0x65, 0x1f, 0xc6, 0x63, 0x05, 0x7c, 0x65, 0xd9, 0x53, 0x0a, 0x3a, 0xc1,
0x03, 0x82, 0xfe, 0xb9, 0x08, 0x2b, 0x68, 0x5a, 0x9b, 0x23, 0x4f, 0x61, 0xa5, 0x1f, 0xa3, 0x75,
0x32, 0xdf, 0x57, 0xe6, 0xe2, 0x72, 0xf1, 0x2c, 0x4e, 0x28, 0xb4, 0x7e, 0x48, 0x24, 0x33, 0x81,
0x05, 0xe5, 0x48, 0xdf, 0x15, 0xae, 0xa7, 0x67, 0x2c, 0xc5, 0xcf, 0xd8, 0x85, 0x6d, 0x74, 0x10,
0x6f, 0x79, 0xe2, 0x68, 0x72, 0xda, 0x0d, 0x4f, 0xa8, 0x3a, 0xd7, 0x48, 0x77, 0xb7, 0x92, 0x3b,
0x9a, 0x9e, 0xb8, 0x94, 0x7d, 0x62, 0xfa, 0x97, 0x22, 0xec, 0xa0, 0xc9, 0x53, 0xef, 0xea, 0xbf,
0x6f, 0x11, 0x2d, 0xa8, 0x7e, 0xf4, 0x85, 0xc4, 0xd3, 0x04, 0x7d, 0x2d, 0xa2, 0xa7, 0xa1, 0x94,
0x73, 0x42, 0xe9, 0x01, 0xc1, 0x48, 0xce, 0xb9, 0xc3, 0x78, 0xe4, 0x7a, 0x0b, 0x6a, 0x76, 0x1f,
0x4f, 0x1f, 0x79, 0x9d, 0x32, 0x6e, 0x3f, 0xdf, 0x4b, 0xd8, 0x40, 0xa3, 0x2f, 0xde, 0x76, 0xce,
0x7a, 0x4c, 0x46, 0x66, 0x9b, 0xb0, 0x78, 0xed, 0x7a, 0x8e, 0x7f, 0xad, 0x6d, 0x6a, 0x2a, 0xbf,
0xc9, 0xd1, 0x7d, 0xd8, 0xd0, 0x46, 0x8e, 0xbf, 0xb8, 0x62, 0x6a, 0x29, 0xa6, 0x51, 0x4c, 0x6a,
0x74, 0xa1, 0xdd, 0xe5, 0xec, 0xca, 0xf5, 0xc7, 0x22, 0x96, 0x94, 0x49, 0xed, 0xbc, 0x46, 0xb6,
0x01, 0x15, 0xce, 0x06, 0xa7, 0x9d, 0xf0, 0xfd, 0x91, 0x50, 0x15, 0x16, 0xa8, 0x2b, 0x3d, 0x86,
0x2b, 0xd4, 0xab, 0x5a, 0x9a, 0xa2, 0x12, 0xea, 0x87, 0x8e, 0x13, 0x94, 0x61, 0xe8, 0x23, 0xb2,
0x55, 0x8c, 0xd9, 0x8a, 0xd5, 0x68, 0x29, 0xd1, 0xe9, 0x0c, 0x58, 0xea, 0x73, 0x86, 0x9d, 0x2c,
0x68, 0xe8, 0x21, 0xa9, 0x76, 0x18, 0x16, 0xbc, 0xd0, 0x3d, 0x2e, 0x24, 0x55, 0x85, 0x6c, 0x1e,
0x3a, 0x4e, 0xec, 0x94, 0xa1, 0xef, 0x3a, 0x94, 0x1d, 0xc6, 0xc3, 0x79, 0xeb, 0x30, 0x9e, 0x7d,
0x32, 0x55, 0x03, 0xaa, 0x17, 0xa1, 0xcb, 0x15, 0x0b, 0xd7, 0x2a, 0x42, 0x57, 0x88, 0x71, 0xd4,
0x52, 0x35, 0xa5, 0xb2, 0x0c, 0x57, 0xfc, 0xb4, 0xa3, 0xdb, 0x68, 0x44, 0xd3, 0x7d, 0x68, 0xa6,
0x03, 0xd1, 0xdd, 0x4d, 0xdd, 0xb4, 0x3b, 0x08, 0x1b, 0x8e, 0xba, 0x69, 0xa4, 0x68, 0x17, 0x56,
0x30, 0xe3, 0xe2, 0x25, 0x14, 0xc3, 0x0f, 0x64, 0x1f, 0xee, 0x8d, 0x05, 0xbb, 0x30, 0x93, 0x95,
0x81, 0xd1, 0x57, 0xad, 0xac, 0x2d, 0xfa, 0x1a, 0x68, 0x38, 0x71, 0xd1, 0x72, 0x76, 0x4d, 0xa5,
0xfd, 0x34, 0x61, 0xd1, 0xee, 0xf7, 0x65, 0x74, 0x31, 0x9a, 0xa2, 0x13, 0xf8, 0xc9, 0x09, 0x0b,
0x8a, 0xe2, 0x85, 0xcf, 0x13, 0xfd, 0x6c, 0xaa, 0x52, 0x8c, 0xab, 0x64, 0xb7, 0xb1, 0xbc, 0x83,
0x94, 0xf3, 0x0f, 0xf2, 0xb7, 0x22, 0x18, 0x27, 0x4c, 0xfe, 0xdf, 0x60, 0x83, 0x9a, 0xa6, 0x9c,
0x7d, 0x1e, 0xbb, 0x5c, 0xc7, 0x72, 0x13, 0x64, 0x5a, 0xd5, 0x4a, 0xb3, 0xe9, 0x5f, 0x8b, 0xb0,
0x96, 0xc2, 0x16, 0x3f, 0x0f, 0x67, 0x7f, 0xd0, 0x8e, 0xb7, 0x55, 0x2f, 0x98, 0x03, 0x2b, 0x50,
0xf6, 0x7f, 0x0f, 0x2b, 0x5e, 0xc3, 0xc3, 0x43, 0xc7, 0xc9, 0x82, 0x8a, 0xd1, 0xcd, 0x7d, 0x9b,
0x0c, 0x74, 0x9e, 0xb5, 0x47, 0x50, 0x4f, 0x81, 0x53, 0xbc, 0x36, 0xd7, 0x09, 0x9b, 0x8d, 0x5a,
0x52, 0x3a, 0x23, 0x65, 0xce, 0xc0, 0xe0, 0x6f, 0xa0, 0x91, 0x90, 0x31, 0x53, 0xa6, 0xca, 0x81,
0xa9, 0x1b, 0x30, 0x2c, 0x84, 0x1b, 0x19, 0xb5, 0x3c, 0x07, 0x1b, 0xf1, 0x00, 0xb0, 0xe8, 0xcc,
0x0d, 0x28, 0x55, 0xd3, 0x0a, 0xfa, 0xe8, 0x07, 0xc6, 0xb5, 0xaa, 0x5d, 0x1e, 0x62, 0x90, 0x05,
0xac, 0xf5, 0x88, 0xa6, 0x7f, 0x2a, 0xc1, 0xd6, 0x0b, 0xd7, 0xb3, 0x87, 0xee, 0x0d, 0xcb, 0x04,
0xd9, 0x19, 0x25, 0xa3, 0x41, 0x59, 0x29, 0x01, 0xca, 0x62, 0x8d, 0xaa, 0x9c, 0x68, 0x54, 0x38,
0x4d, 0xa4, 0x64, 0x97, 0xa3, 0x10, 0xa8, 0xd5, 0xac, 0x29, 0x83, 0x74, 0xa0, 0x81, 0x43, 0x50,
0x3b, 0xed, 0xfb, 0xdc, 0x11, 0x46, 0x05, 0x1f, 0xa9, 0x19, 0x3c, 0xd2, 0x45, 0x6a, 0xdb, 0x9a,
0x55, 0x20, 0x4f, 0x60, 0x7d, 0xca, 0x3c, 0xe6, 0xdc, 0xe7, 0x08, 0xe4, 0x96, 0xcd, 0x8d, 0xc0,
0x46, 0x97, 0xfb, 0xef, 0x87, 0xec, 0xb2, 0xc3, 0xa4, 0xed, 0x0e, 0x85, 0x95, 0x16, 0x36, 0xff,
0x4e, 0xa0, 0xde, 0x93, 0x3e, 0xb7, 0x07, 0xe1, 0x2d, 0xc8, 0x09, 0x39, 0x80, 0xf5, 0x13, 0x96,
0x98, 0xfb, 0x84, 0xe0, 0xb0, 0x4b, 0x14, 0x5b, 0x8b, 0x04, 0x2e, 0xe2, 0x5c, 0x5a, 0x20, 0xbf,
0x84, 0x8d, 0x94, 0xf2, 0xd1, 0x44, 0x7d, 0x0c, 0xad, 0x29, 0x0b, 0xd3, 0x8f, 0xa3, 0x1c, 0xed,
0x9f, 0xc1, 0xda, 0x09, 0x8b, 0xc3, 0x2a, 0x02, 0x4a, 0x2f, 0x98, 0x31, 0xad, 0x46, 0xa0, 0x13,
0xdb, 0xa6, 0x05, 0xf2, 0x3d, 0x34, 0xd4, 0xf7, 0x12, 0x67, 0xfd, 0xbb, 0x68, 0x1d, 0x60, 0x98,
0xb3, 0x98, 0x3c, 0xae, 0xb8, 0x89, 0x20, 0x2b, 0x2d, 0x42, 0x0b, 0xa4, 0x07, 0x46, 0x1e, 0xfc,
0x23, 0x5f, 0x47, 0xc8, 0x2c, 0x1f, 0x1c, 0xb6, 0xea, 0x69, 0xf8, 0x46, 0x0b, 0xe4, 0x25, 0x34,
0xb3, 0xf1, 0x16, 0xd9, 0x89, 0xa4, 0xf3, 0xb0, 0x58, 0xab, 0x16, 0x89, 0xd0, 0x02, 0x79, 0x03,
0xf7, 0x73, 0xa4, 0x11, 0x78, 0xde, 0xd5, 0x9c, 0x09, 0xcb, 0x31, 0xac, 0x44, 0x9a, 0xd1, 0x5e,
0x02, 0x3c, 0x25, 0x75, 0x7e, 0x80, 0xd5, 0x04, 0x14, 0x22, 0x46, 0xb4, 0x9b, 0x42, 0x47, 0x49,
0xbd, 0x1f, 0x61, 0x35, 0x01, 0x7c, 0x02, 0xbd, 0x2c, 0x2c, 0xd4, 0xc2, 0x97, 0x0a, 0x58, 0xb4,
0x40, 0xce, 0xe1, 0xab, 0x5c, 0xfc, 0x43, 0x1e, 0x29, 0xd1, 0xdb, 0xe0, 0x51, 0xca, 0xe0, 0x33,
0x4c, 0xab, 0x64, 0x1b, 0x23, 0x1b, 0x33, 0x7d, 0xfe, 0xb4, 0x63, 0xb6, 0xb2, 0x9a, 0x2a, 0x3e,
0x28, 0x99, 0x19, 0x68, 0x26, 0xd9, 0x52, 0x26, 0xf2, 0x06, 0x5d, 0x8b, 0xcc, 0x0e, 0x12, 0x5a,
0x20, 0xef, 0x70, 0x34, 0x66, 0xf5, 0x79, 0x93, 0x50, 0x6d, 0x6f, 0xce, 0x0f, 0x83, 0xbc, 0x00,
0x9f, 0xe8, 0x3c, 0xc9, 0x1c, 0x20, 0x66, 0x66, 0xcd, 0x27, 0x1e, 0xeb, 0x0f, 0xb0, 0x35, 0x07,
0x7b, 0x98, 0xe4, 0xb1, 0x0e, 0xed, 0x16, 0x74, 0x92, 0x73, 0xe8, 0xb7, 0x3a, 0xba, 0xcc, 0x8f,
0x05, 0x93, 0x7c, 0x13, 0x45, 0x32, 0xef, 0x6b, 0x22, 0x19, 0xb0, 0x85, 0xf0, 0xe6, 0x22, 0xcb,
0xdc, 0x4e, 0x3c, 0xd6, 0xbb, 0x84, 0x79, 0x00, 0xeb, 0x67, 0xec, 0x3a, 0xd5, 0x2c, 0x67, 0x5a,
0x5b, 0x4e, 0xbb, 0xfb, 0x11, 0x48, 0xf0, 0xc9, 0x7e, 0xab, 0xfe, 0x72, 0xc0, 0x3b, 0xbe, 0x1c,
0xc9, 0x09, 0x2d, 0x90, 0x53, 0x58, 0x4b, 0x42, 0x4f, 0xf2, 0x15, 0x46, 0x97, 0x85, 0x8b, 0x5b,
0xad, 0xac, 0x2d, 0x3d, 0x07, 0x0b, 0xe4, 0x57, 0xd0, 0x50, 0x20, 0x22, 0xd9, 0x3f, 0xe7, 0x58,
0x4b, 0x45, 0xb2, 0x0f, 0xb5, 0xe8, 0x23, 0x40, 0xd7, 0x47, 0xea, 0x9b, 0x20, 0xad, 0x71, 0x00,
0xcd, 0x0e, 0xb3, 0xfb, 0xd2, 0xbd, 0x9a, 0x3d, 0xf8, 0x6c, 0xc6, 0xa5, 0x94, 0x1f, 0x43, 0xf5,
0x8c, 0x5d, 0x63, 0x32, 0x11, 0xbd, 0x85, 0x44, 0x2b, 0x4e, 0x60, 0x58, 0xa4, 0xa7, 0x91, 0x6c,
0x97, 0xfb, 0x7d, 0x26, 0x84, 0xeb, 0x0d, 0x32, 0x35, 0x42, 0xcb, 0x3f, 0x85, 0xd5, 0x50, 0x03,
0x67, 0xe3, 0x6d, 0xc2, 0x21, 0x7a, 0xc8, 0x8f, 0x65, 0x2a, 0x5c, 0x0d, 0x51, 0x35, 0xc1, 0xce,
0x1f, 0xff, 0x06, 0x48, 0x07, 0xfe, 0x04, 0xea, 0x69, 0x08, 0x4e, 0xee, 0xeb, 0xe4, 0xcc, 0x02,
0xe6, 0x69, 0xfd, 0x67, 0xd0, 0x98, 0x01, 0x55, 0x41, 0xd3, 0xc9, 0xc3, 0x5a, 0xe9, 0x70, 0x2d,
0x20, 0x67, 0xec, 0x3a, 0x5d, 0x20, 0x5f, 0xeb, 0xa7, 0x9d, 0x87, 0x36, 0x83, 0x89, 0x39, 0x03,
0xfd, 0x30, 0x5f, 0x9b, 0x99, 0x68, 0xcb, 0x24, 0x6d, 0x6c, 0xf0, 0x73, 0x90, 0x58, 0x3a, 0xbc,
0xa7, 0x60, 0x4c, 0xd3, 0xe7, 0x3f, 0xea, 0xcf, 0x29, 0x03, 0xbb, 0xb0, 0x12, 0xe4, 0xa7, 0x9e,
0x0e, 0xf1, 0x91, 0x9f, 0x98, 0x01, 0x47, 0x4b, 0xbf, 0xaf, 0xe0, 0x9f, 0xdf, 0x7f, 0x07, 0x00,
0x00, 0xff, 0xff, 0x71, 0xbc, 0xd9, 0x84, 0x28, 0x16, 0x00, 0x00,
// 1830 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xeb, 0x72, 0x1b, 0xb7,
0x15, 0xe6, 0xc5, 0x94, 0xc9, 0xa3, 0x2b, 0x61, 0x99, 0xdd, 0xd0, 0xb2, 0x4d, 0x23, 0x8e, 0x47,
0x99, 0x4e, 0x15, 0x67, 0x9b, 0x49, 0x32, 0xa3, 0xd6, 0x89, 0x14, 0xca, 0xb2, 0x62, 0x47, 0x66,
0x96, 0xb5, 0xda, 0xe9, 0xf4, 0xcf, 0x86, 0x8b, 0xd0, 0x5b, 0x53, 0xbb, 0x0c, 0x00, 0x4a, 0xa6,
0x7e, 0x77, 0xa6, 0x79, 0x82, 0x4e, 0x7f, 0xf6, 0x39, 0xfa, 0x12, 0x7d, 0xa5, 0x0e, 0x0e, 0xb0,
0x57, 0xee, 0x52, 0xd5, 0xb4, 0xd3, 0x7f, 0x7b, 0x0e, 0xce, 0x0d, 0xc0, 0xb9, 0x7c, 0x58, 0x68,
0x0b, 0xf7, 0x93, 0x29, 0x0f, 0x65, 0xf8, 0x89, 0x70, 0xf7, 0xf0, 0x83, 0xd4, 0x84, 0xdb, 0xbd,
0x3b, 0x0a, 0x39, 0x33, 0x0b, 0xea, 0x53, 0x2f, 0xd1, 0x1e, 0x6c, 0x38, 0x6c, 0xec, 0x0b, 0xc9,
0x5d, 0xe9, 0x87, 0xc1, 0x49, 0x9f, 0x6c, 0x40, 0xcd, 0xf7, 0xac, 0x6a, 0xaf, 0xba, 0x5b, 0x77,
0x6a, 0xbe, 0x47, 0x1f, 0x00, 0x7c, 0x3b, 0x7c, 0x7d, 0xfa, 0x7b, 0xf6, 0xc3, 0x4b, 0x36, 0x27,
0x5b, 0x50, 0xff, 0xf3, 0xe5, 0x3b, 0x5c, 0x5e, 0x73, 0xd4, 0x27, 0x7d, 0x04, 0x9b, 0x07, 0x33,
0xf9, 0x36, 0xe4, 0xfe, 0xd5, 0xa2, 0x89, 0x16, 0x9a, 0xf8, 0x67, 0x15, 0x1e, 0x1c, 0x33, 0x39,
0x60, 0x81, 0xe7, 0x07, 0xe3, 0x8c, 0xb4, 0xc3, 0x7e, 0x9a, 0x31, 0x21, 0xc9, 0x13, 0xd8, 0xe0,
0x99, 0x38, 0x4c, 0x04, 0x39, 0xae, 0x92, 0xf3, 0x3d, 0x16, 0x48, 0xff, 0x47, 0x9f, 0xf1, 0xdf,
0xcd, 0xa7, 0xcc, 0xaa, 0xa1, 0x9b, 0x1c, 0x97, 0xec, 0xc2, 0x66, 0xc2, 0x39, 0x73, 0x27, 0x33,
0x66, 0xd5, 0x51, 0x30, 0xcf, 0x26, 0x0f, 0x00, 0x2e, 0xdc, 0x89, 0xef, 0xbd, 0x09, 0xa4, 0x3f,
0xb1, 0x6e, 0xa1, 0xd7, 0x14, 0x87, 0x0a, 0xb8, 0x7f, 0xcc, 0xe4, 0x99, 0x62, 0x64, 0x22, 0x17,
0x37, 0x0d, 0xdd, 0x82, 0xdb, 0x5e, 0x78, 0xee, 0xfa, 0x81, 0xb0, 0x6a, 0xbd, 0xfa, 0x6e, 0xcb,
0x89, 0x48, 0x75, 0xa8, 0x41, 0x78, 0x89, 0x01, 0xd6, 0x1d, 0xf5, 0x49, 0xff, 0x51, 0x85, 0x3b,
0x05, 0x2e, 0xc9, 0x97, 0xd0, 0xc0, 0xd0, 0xac, 0x6a, 0xaf, 0xbe, 0xbb, 0x6a, 0xd3, 0x3d, 0xe1,
0xee, 0x15, 0xc8, 0xed, 0x7d, 0xe7, 0x4e, 0x8f, 0x26, 0xec, 0x9c, 0x05, 0xd2, 0xd1, 0x0a, 0xdd,
0xd7, 0x00, 0x09, 0x93, 0x74, 0x60, 0x45, 0x3b, 0x37, 0xb7, 0x64, 0x28, 0xf2, 0x31, 0x34, 0xdc,
0x99, 0x7c, 0x7b, 0x85, 0xa7, 0xba, 0x6a, 0xdf, 0xd9, 0xc3, 0x54, 0xc9, 0xde, 0x98, 0x96, 0xa0,
0xff, 0xaa, 0x41, 0xfb, 0x1b, 0xc6, 0xd5, 0x51, 0x8e, 0x5c, 0xc9, 0x86, 0xd2, 0x95, 0x33, 0xa1,
0x0c, 0x0b, 0xc6, 0x7d, 0x77, 0x12, 0x19, 0xd6, 0x14, 0xf2, 0x51, 0xc2, 0x5c, 0x83, 0xa1, 0xd4,
0x3d, 0x85, 0x23, 0x31, 0x7d, 0xe5, 0x0a, 0xf9, 0x66, 0xea, 0xb9, 0x92, 0x79, 0xe6, 0x0a, 0xf2,
0x6c, 0xd2, 0x83, 0x55, 0xce, 0x2e, 0xc2, 0x77, 0xcc, 0xeb, 0xbb, 0x92, 0x59, 0x0d, 0x94, 0x4a,
0xb3, 0xc8, 0x63, 0x58, 0x37, 0xa4, 0xc3, 0x5c, 0x11, 0x06, 0xd6, 0x0a, 0xca, 0x64, 0x99, 0xe4,
0x33, 0xb8, 0x3b, 0x71, 0x85, 0x3c, 0x7a, 0x3f, 0xf5, 0xf5, 0xd5, 0x9c, 0xba, 0xe3, 0x21, 0x0b,
0xa4, 0x75, 0x1b, 0xa5, 0x8b, 0x17, 0x09, 0x85, 0x35, 0x15, 0x90, 0xc3, 0xc4, 0x34, 0x0c, 0x04,
0xb3, 0x9a, 0x58, 0x00, 0x19, 0x1e, 0xe9, 0x42, 0x33, 0x08, 0xe5, 0xc1, 0x8f, 0x92, 0x71, 0xab,
0x85, 0xc6, 0x62, 0x9a, 0xec, 0x40, 0xcb, 0x17, 0x68, 0x96, 0x79, 0x16, 0xf4, 0xaa, 0xbb, 0x4d,
0x27, 0x61, 0x7c, 0x7b, 0xab, 0x59, 0xdb, 0xaa, 0xd3, 0x1e, 0xac, 0x0c, 0x93, 0xd3, 0x2a, 0x38,
0x45, 0xba, 0x0f, 0x0d, 0xc7, 0x0d, 0xc6, 0xe8, 0x8a, 0xb9, 0x7c, 0xe2, 0x33, 0x21, 0x4d, 0xb6,
0xc5, 0xb4, 0x52, 0x9e, 0xb8, 0x52, 0xad, 0xd4, 0x70, 0xc5, 0x50, 0xf4, 0x3e, 0x34, 0xbe, 0x09,
0x67, 0x81, 0x24, 0xdb, 0xd0, 0x18, 0xa9, 0x0f, 0xa3, 0xa9, 0x09, 0xfa, 0x07, 0x78, 0x88, 0xcb,
0xa9, 0x3b, 0x15, 0x87, 0xf3, 0x53, 0xf7, 0x9c, 0xc5, 0x99, 0xfe, 0x10, 0x1a, 0x5c, 0xb9, 0x47,
0xc5, 0x55, 0xbb, 0xa5, 0xb2, 0x0f, 0xe3, 0x71, 0x34, 0x5f, 0x59, 0x0e, 0x94, 0x82, 0x49, 0x70,
0x4d, 0xd0, 0xbf, 0x56, 0x61, 0x0d, 0x4d, 0x1b, 0x73, 0xe4, 0x2b, 0x58, 0x1b, 0xa5, 0x68, 0x93,
0xcc, 0xf7, 0x94, 0xb9, 0xb4, 0x5c, 0x3a, 0x8b, 0x33, 0x0a, 0xdd, 0xcf, 0x33, 0xc9, 0x4c, 0xe0,
0x96, 0x72, 0x64, 0xce, 0x0a, 0xbf, 0x93, 0x3d, 0xd6, 0xd2, 0x7b, 0x1c, 0xc0, 0x7d, 0x74, 0x90,
0x6e, 0x79, 0xe2, 0x70, 0x7e, 0x32, 0x88, 0x76, 0xa8, 0x3a, 0xd7, 0xd4, 0x74, 0xb7, 0x9a, 0x3f,
0x4d, 0x76, 0x5c, 0x2b, 0xde, 0x31, 0xfd, 0xb9, 0x0a, 0x8f, 0xd0, 0xe4, 0x49, 0x70, 0xf1, 0xdf,
0xb7, 0x88, 0x2e, 0x34, 0xdf, 0x86, 0x42, 0xe2, 0x6e, 0x74, 0x5f, 0x8b, 0xe9, 0x24, 0x94, 0x7a,
0x49, 0x28, 0x43, 0x20, 0x18, 0xc9, 0x6b, 0xee, 0x31, 0x1e, 0xbb, 0xde, 0x81, 0x96, 0x3b, 0xc2,
0xdd, 0xc7, 0x5e, 0x13, 0xc6, 0xf5, 0xfb, 0x7b, 0x01, 0xdb, 0x68, 0xf4, 0xf9, 0xf7, 0xfd, 0xd3,
0x21, 0x93, 0xb1, 0xd9, 0x0e, 0xac, 0x5c, 0xfa, 0x81, 0x17, 0x5e, 0x1a, 0x9b, 0x86, 0x2a, 0x6f,
0x72, 0xf4, 0x29, 0x6c, 0x1b, 0x23, 0x47, 0xef, 0x7d, 0x91, 0x58, 0x4a, 0x69, 0x54, 0xb3, 0x1a,
0x03, 0xe8, 0x0d, 0x38, 0xbb, 0xf0, 0xc3, 0x99, 0x48, 0x25, 0x65, 0x56, 0xbb, 0xac, 0x91, 0x6d,
0x43, 0x83, 0xb3, 0xf1, 0x49, 0x3f, 0xba, 0x7f, 0x24, 0x54, 0x85, 0x69, 0x75, 0xa5, 0xc7, 0xf0,
0x0b, 0xf5, 0x9a, 0x8e, 0xa1, 0xa8, 0x84, 0xad, 0x03, 0xcf, 0xd3, 0x65, 0x18, 0xf9, 0x88, 0x6d,
0x55, 0x53, 0xb6, 0x52, 0x35, 0x5a, 0xcb, 0x74, 0x3a, 0x0b, 0x6e, 0x8f, 0x38, 0xc3, 0x4e, 0xa6,
0x1b, 0x7a, 0x44, 0xaa, 0x15, 0x86, 0x05, 0x2f, 0x4c, 0x8f, 0x8b, 0x48, 0x55, 0x21, 0x77, 0x0f,
0x3c, 0x2f, 0xb5, 0xcb, 0xc8, 0xf7, 0x16, 0xd4, 0x3d, 0xc6, 0xa3, 0x79, 0xeb, 0x31, 0x5e, 0xbc,
0x33, 0x55, 0x03, 0xaa, 0x17, 0xa1, 0xcb, 0x35, 0x07, 0xbf, 0x55, 0x84, 0xbe, 0x10, 0xb3, 0xb8,
0xa5, 0x1a, 0x4a, 0x65, 0x19, 0x7e, 0xf1, 0x93, 0xbe, 0x69, 0xa3, 0x31, 0x4d, 0x9f, 0x42, 0x27,
0x1f, 0x88, 0xe9, 0x6e, 0xea, 0xa4, 0xfd, 0x71, 0xd4, 0x70, 0xd4, 0x49, 0x23, 0x45, 0x07, 0xb0,
0x86, 0x19, 0x97, 0x2e, 0xa1, 0x14, 0x7e, 0x20, 0x4f, 0xe1, 0xce, 0x4c, 0xb0, 0x33, 0x3b, 0x5b,
0x19, 0x18, 0x7d, 0xd3, 0x29, 0x5a, 0xa2, 0xaf, 0x80, 0x46, 0x13, 0x17, 0x2d, 0x17, 0xd7, 0x54,
0xde, 0x4f, 0x07, 0x56, 0xdc, 0xd1, 0x48, 0xc6, 0x07, 0x63, 0x28, 0x3a, 0x87, 0x5f, 0x1c, 0x33,
0x5d, 0x14, 0xcf, 0x43, 0x9e, 0xe9, 0x67, 0x89, 0x4a, 0x35, 0xad, 0x52, 0xdc, 0xc6, 0xca, 0x36,
0x52, 0x2f, 0xdf, 0xc8, 0xdf, 0xab, 0x60, 0x1d, 0x33, 0xf9, 0x7f, 0x83, 0x0d, 0x6a, 0x9a, 0x72,
0xf6, 0xd3, 0xcc, 0xe7, 0x26, 0x96, 0x2b, 0x9d, 0x69, 0x4d, 0x27, 0xcf, 0xa6, 0x7f, 0xab, 0xc2,
0x46, 0x0e, 0x5b, 0xfc, 0x3a, 0x9a, 0xfd, 0xba, 0x1d, 0xdf, 0x57, 0xbd, 0x60, 0x09, 0xac, 0x40,
0xd9, 0xff, 0x3d, 0xac, 0x78, 0x05, 0x0f, 0x0f, 0x3c, 0xaf, 0x08, 0x2a, 0xc6, 0x27, 0xf7, 0x71,
0x36, 0xd0, 0x65, 0xd6, 0x1e, 0xc3, 0x56, 0x0e, 0x9c, 0xe2, 0xb1, 0xf9, 0x5e, 0xd4, 0x6c, 0xd4,
0x27, 0xa5, 0x0b, 0x52, 0xf6, 0x02, 0x0c, 0xfe, 0x08, 0xda, 0x19, 0x19, 0x3b, 0x67, 0xaa, 0xae,
0x4d, 0x5d, 0x81, 0xe5, 0x20, 0xdc, 0x28, 0xa8, 0xe5, 0x25, 0xd8, 0x88, 0x6b, 0xc0, 0x62, 0x32,
0x57, 0x53, 0xaa, 0xa6, 0x15, 0xf4, 0x31, 0x17, 0x8c, 0xdf, 0xaa, 0x76, 0x79, 0x84, 0x41, 0x6e,
0x61, 0xad, 0xc7, 0x34, 0xfd, 0x4b, 0x0d, 0x76, 0x9e, 0xfb, 0x81, 0x3b, 0xf1, 0xaf, 0x58, 0x21,
0xc8, 0x2e, 0x28, 0x19, 0x03, 0xca, 0x6a, 0x19, 0x50, 0x96, 0x6a, 0x54, 0xf5, 0x4c, 0xa3, 0xc2,
0x69, 0x22, 0x25, 0x3b, 0x9f, 0x46, 0x40, 0xad, 0xe5, 0x24, 0x0c, 0xd2, 0x87, 0x36, 0x0e, 0x41,
0xe3, 0x74, 0x14, 0x72, 0x4f, 0x58, 0x0d, 0xbc, 0xa4, 0x8e, 0xbe, 0xa4, 0xb3, 0xdc, 0xb2, 0xb3,
0xa8, 0x40, 0x9e, 0xc1, 0x66, 0xc2, 0x3c, 0xe2, 0x3c, 0xe4, 0x08, 0xe4, 0x56, 0xed, 0x6d, 0x6d,
0x63, 0xc0, 0xc3, 0x1f, 0x26, 0xec, 0xbc, 0xcf, 0xa4, 0xeb, 0x4f, 0x84, 0x93, 0x17, 0xa6, 0xef,
0x61, 0xfb, 0xc0, 0xf3, 0x0e, 0x27, 0xe1, 0xe8, 0x1d, 0xf3, 0x5e, 0xb2, 0x79, 0x6a, 0xd0, 0xbc,
0x63, 0xf3, 0x17, 0xae, 0x78, 0x6b, 0xda, 0x69, 0x44, 0xaa, 0x7a, 0x77, 0x3d, 0x8f, 0x79, 0x51,
0x4b, 0x45, 0x02, 0x4f, 0x27, 0x9c, 0xf1, 0x11, 0x8b, 0x21, 0x2b, 0x52, 0xd8, 0xe0, 0xc3, 0x73,
0x95, 0xef, 0xe6, 0x04, 0x22, 0x92, 0xfe, 0x0a, 0xda, 0x2f, 0xd9, 0xdc, 0x78, 0xbe, 0xd6, 0xad,
0xfd, 0xf3, 0x1d, 0xd8, 0x1a, 0xca, 0x90, 0xbb, 0xe3, 0xe8, 0xba, 0xe4, 0x9c, 0xec, 0xc3, 0xe6,
0x31, 0xcb, 0x00, 0x14, 0x42, 0x70, 0x2a, 0x67, 0xba, 0x42, 0x97, 0xe8, 0xb3, 0x48, 0x73, 0x69,
0x85, 0xfc, 0x06, 0xb6, 0x73, 0xca, 0x87, 0x73, 0xf5, 0x6a, 0xdb, 0x50, 0x16, 0x92, 0x57, 0x5c,
0x89, 0xf6, 0xa7, 0xb0, 0x71, 0xcc, 0xd2, 0xf8, 0x8f, 0x80, 0xd2, 0xd3, 0xc3, 0xb0, 0xdb, 0xd6,
0x3a, 0xa9, 0x65, 0x5a, 0x21, 0x9f, 0x41, 0x5b, 0x3d, 0xec, 0x38, 0x1b, 0xdd, 0x44, 0x6b, 0x1f,
0xc3, 0x5c, 0x7c, 0x3c, 0xa4, 0x15, 0xef, 0x22, 0x1a, 0xcc, 0x8b, 0xd0, 0x0a, 0x19, 0x82, 0x55,
0x86, 0x53, 0xc9, 0x87, 0x31, 0x84, 0x2c, 0x47, 0xb1, 0xdd, 0xad, 0x3c, 0xce, 0xa4, 0x15, 0xf2,
0x02, 0x3a, 0xc5, 0xc0, 0x90, 0x3c, 0x8a, 0xa5, 0xcb, 0x40, 0x63, 0xb7, 0x15, 0x8b, 0xd0, 0x0a,
0xf9, 0x0e, 0xee, 0x95, 0x48, 0x23, 0x42, 0xbe, 0xa9, 0x39, 0x1b, 0x56, 0x53, 0xa0, 0x8e, 0x74,
0xe2, 0xb5, 0x0c, 0xca, 0xcb, 0xea, 0x7c, 0x0e, 0xeb, 0x19, 0xcc, 0x46, 0xac, 0x78, 0x35, 0x07,
0xe3, 0xb2, 0x7a, 0x5f, 0xc0, 0x7a, 0x06, 0xa1, 0x69, 0xbd, 0x22, 0xd0, 0xd6, 0xc5, 0x9b, 0xd2,
0x2c, 0x5a, 0x21, 0xaf, 0xe1, 0x83, 0x52, 0xa0, 0x46, 0x1e, 0x2b, 0xd1, 0xeb, 0x70, 0x5c, 0xce,
0xe0, 0xd7, 0x98, 0x56, 0xd9, 0x7e, 0x4b, 0xb6, 0x17, 0x06, 0xd2, 0x49, 0xdf, 0xee, 0x16, 0x75,
0x7f, 0xbc, 0x50, 0xb2, 0x30, 0x79, 0x6d, 0xb2, 0xa3, 0x4c, 0x94, 0x4d, 0xe4, 0x2e, 0x59, 0x9c,
0x78, 0xb4, 0x42, 0xde, 0xe0, 0x0c, 0x2f, 0x1a, 0x48, 0x36, 0xa1, 0xc6, 0xde, 0x92, 0x3f, 0x1b,
0x65, 0x01, 0x3e, 0x33, 0x79, 0x52, 0x38, 0xe9, 0xec, 0xc2, 0x9a, 0xcf, 0x5c, 0xd6, 0x9f, 0x60,
0x67, 0x09, 0x48, 0xb2, 0xc9, 0x13, 0x13, 0xda, 0x35, 0x30, 0xaa, 0x64, 0xd3, 0xdf, 0x9b, 0xe8,
0x0a, 0x5f, 0x35, 0x36, 0xf9, 0x28, 0x8e, 0x64, 0xd9, 0xb3, 0x27, 0x1b, 0xb0, 0x83, 0x38, 0xec,
0xac, 0xc8, 0xdc, 0xa3, 0x74, 0xac, 0x37, 0x09, 0xf3, 0x53, 0x80, 0xa4, 0xe1, 0x12, 0x6c, 0x19,
0x0b, 0x0d, 0x38, 0x97, 0x5a, 0xfb, 0xb0, 0x79, 0xca, 0x2e, 0x73, 0xfd, 0x75, 0xa1, 0x1b, 0x96,
0x74, 0xc8, 0x2f, 0x80, 0xe8, 0xdf, 0x11, 0xd7, 0xea, 0xaf, 0x6a, 0xde, 0xd1, 0xf9, 0x54, 0xce,
0x69, 0x85, 0x9c, 0xc0, 0x46, 0x16, 0x56, 0x93, 0x0f, 0x70, 0x43, 0x45, 0x98, 0xbf, 0xdb, 0x2d,
0x5a, 0x32, 0x33, 0xbe, 0x42, 0x7e, 0x0b, 0x6d, 0x05, 0x90, 0xb2, 0x2d, 0x77, 0x89, 0xb5, 0x5c,
0x24, 0x4f, 0xa1, 0x15, 0x3f, 0x70, 0x4c, 0x49, 0xe5, 0xde, 0x3b, 0x79, 0x8d, 0x7d, 0xe8, 0xf4,
0x99, 0x3b, 0x92, 0xfe, 0xc5, 0xe2, 0xc6, 0x17, 0x93, 0x34, 0xa7, 0xfc, 0x04, 0x9a, 0xa7, 0xec,
0x12, 0xf3, 0x8f, 0x98, 0x25, 0x24, 0xba, 0x69, 0x02, 0xc3, 0x22, 0x43, 0x83, 0xd2, 0x07, 0x3c,
0x1c, 0x31, 0x21, 0xfc, 0x60, 0x5c, 0xa8, 0x11, 0x59, 0xfe, 0x25, 0xac, 0x47, 0x1a, 0x38, 0xf7,
0xaf, 0x13, 0x8e, 0x90, 0x51, 0x79, 0x2c, 0x89, 0x70, 0x33, 0x7a, 0x31, 0x10, 0x1c, 0x16, 0xe9,
0xf7, 0x4d, 0x3e, 0xf0, 0x67, 0xb0, 0x95, 0x7f, 0x5e, 0x90, 0x7b, 0x26, 0x9f, 0x8b, 0x1e, 0x1d,
0x79, 0xfd, 0xaf, 0xa1, 0xbd, 0x00, 0x18, 0x75, 0x9f, 0x2a, 0xc3, 0x91, 0xf9, 0x70, 0x1d, 0x20,
0xa7, 0xec, 0x32, 0x5f, 0x53, 0x1f, 0x9a, 0xab, 0x5d, 0x86, 0xa4, 0xf5, 0x90, 0x5d, 0x80, 0xb5,
0x98, 0xaf, 0x9d, 0x42, 0x24, 0x69, 0x93, 0x1e, 0xce, 0x84, 0x25, 0x28, 0x33, 0x1f, 0xde, 0x57,
0x60, 0x25, 0xe9, 0xf3, 0x1f, 0xb5, 0xf4, 0x9c, 0x81, 0x5d, 0x58, 0xd3, 0xf9, 0x69, 0x06, 0x4a,
0x1a, 0x25, 0x64, 0x6b, 0xfb, 0x4b, 0x58, 0xcf, 0x20, 0x3f, 0x3d, 0xc0, 0x8a, 0xc0, 0x60, 0xce,
0xc7, 0xe1, 0xed, 0x3f, 0x36, 0xf0, 0x7f, 0xf8, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x26, 0xa2,
0x44, 0x9d, 0x3e, 0x17, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -1992,6 +2102,7 @@ type StorageAuthorityClient interface {
GetValidOrderAuthorizations2(ctx context.Context, in *GetValidOrderAuthorizationsRequest, opts ...grpc.CallOption) (*Authorizations, error)
CountInvalidAuthorizations2(ctx context.Context, in *CountInvalidAuthorizationsRequest, opts ...grpc.CallOption) (*Count, error)
GetValidAuthorizations2(ctx context.Context, in *GetValidAuthorizationsRequest, opts ...grpc.CallOption) (*Authorizations, error)
KeyBlocked(ctx context.Context, in *KeyBlockedRequest, opts ...grpc.CallOption) (*Exists, error)
// Adders
NewRegistration(ctx context.Context, in *proto1.Registration, opts ...grpc.CallOption) (*proto1.Registration, error)
UpdateRegistration(ctx context.Context, in *proto1.Registration, opts ...grpc.CallOption) (*proto1.Empty, error)
@ -2010,6 +2121,7 @@ type StorageAuthorityClient interface {
FinalizeAuthorization2(ctx context.Context, in *FinalizeAuthorizationRequest, opts ...grpc.CallOption) (*proto1.Empty, error)
DeactivateAuthorization2(ctx context.Context, in *AuthorizationID2, opts ...grpc.CallOption) (*proto1.Empty, error)
SerialExists(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Exists, error)
AddBlockedKey(ctx context.Context, in *AddBlockedKeyRequest, opts ...grpc.CallOption) (*proto1.Empty, error)
}
type storageAuthorityClient struct {
@ -2191,6 +2303,15 @@ func (c *storageAuthorityClient) GetValidAuthorizations2(ctx context.Context, in
return out, nil
}
func (c *storageAuthorityClient) KeyBlocked(ctx context.Context, in *KeyBlockedRequest, opts ...grpc.CallOption) (*Exists, error) {
out := new(Exists)
err := c.cc.Invoke(ctx, "/sa.StorageAuthority/KeyBlocked", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *storageAuthorityClient) NewRegistration(ctx context.Context, in *proto1.Registration, opts ...grpc.CallOption) (*proto1.Registration, error) {
out := new(proto1.Registration)
err := c.cc.Invoke(ctx, "/sa.StorageAuthority/NewRegistration", in, out, opts...)
@ -2344,6 +2465,15 @@ func (c *storageAuthorityClient) SerialExists(ctx context.Context, in *Serial, o
return out, nil
}
func (c *storageAuthorityClient) AddBlockedKey(ctx context.Context, in *AddBlockedKeyRequest, opts ...grpc.CallOption) (*proto1.Empty, error) {
out := new(proto1.Empty)
err := c.cc.Invoke(ctx, "/sa.StorageAuthority/AddBlockedKey", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// StorageAuthorityServer is the server API for StorageAuthority service.
type StorageAuthorityServer interface {
// Getters
@ -2368,6 +2498,7 @@ type StorageAuthorityServer interface {
GetValidOrderAuthorizations2(context.Context, *GetValidOrderAuthorizationsRequest) (*Authorizations, error)
CountInvalidAuthorizations2(context.Context, *CountInvalidAuthorizationsRequest) (*Count, error)
GetValidAuthorizations2(context.Context, *GetValidAuthorizationsRequest) (*Authorizations, error)
KeyBlocked(context.Context, *KeyBlockedRequest) (*Exists, error)
// Adders
NewRegistration(context.Context, *proto1.Registration) (*proto1.Registration, error)
UpdateRegistration(context.Context, *proto1.Registration) (*proto1.Empty, error)
@ -2386,6 +2517,7 @@ type StorageAuthorityServer interface {
FinalizeAuthorization2(context.Context, *FinalizeAuthorizationRequest) (*proto1.Empty, error)
DeactivateAuthorization2(context.Context, *AuthorizationID2) (*proto1.Empty, error)
SerialExists(context.Context, *Serial) (*Exists, error)
AddBlockedKey(context.Context, *AddBlockedKeyRequest) (*proto1.Empty, error)
}
// UnimplementedStorageAuthorityServer can be embedded to have forward compatible implementations.
@ -2449,6 +2581,9 @@ func (*UnimplementedStorageAuthorityServer) CountInvalidAuthorizations2(ctx cont
func (*UnimplementedStorageAuthorityServer) GetValidAuthorizations2(ctx context.Context, req *GetValidAuthorizationsRequest) (*Authorizations, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetValidAuthorizations2 not implemented")
}
func (*UnimplementedStorageAuthorityServer) KeyBlocked(ctx context.Context, req *KeyBlockedRequest) (*Exists, error) {
return nil, status.Errorf(codes.Unimplemented, "method KeyBlocked not implemented")
}
func (*UnimplementedStorageAuthorityServer) NewRegistration(ctx context.Context, req *proto1.Registration) (*proto1.Registration, error) {
return nil, status.Errorf(codes.Unimplemented, "method NewRegistration not implemented")
}
@ -2500,6 +2635,9 @@ func (*UnimplementedStorageAuthorityServer) DeactivateAuthorization2(ctx context
func (*UnimplementedStorageAuthorityServer) SerialExists(ctx context.Context, req *Serial) (*Exists, error) {
return nil, status.Errorf(codes.Unimplemented, "method SerialExists not implemented")
}
func (*UnimplementedStorageAuthorityServer) AddBlockedKey(ctx context.Context, req *AddBlockedKeyRequest) (*proto1.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddBlockedKey not implemented")
}
func RegisterStorageAuthorityServer(s *grpc.Server, srv StorageAuthorityServer) {
s.RegisterService(&_StorageAuthority_serviceDesc, srv)
@ -2847,6 +2985,24 @@ func _StorageAuthority_GetValidAuthorizations2_Handler(srv interface{}, ctx cont
return interceptor(ctx, in, info, handler)
}
func _StorageAuthority_KeyBlocked_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(KeyBlockedRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageAuthorityServer).KeyBlocked(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/sa.StorageAuthority/KeyBlocked",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageAuthorityServer).KeyBlocked(ctx, req.(*KeyBlockedRequest))
}
return interceptor(ctx, in, info, handler)
}
func _StorageAuthority_NewRegistration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(proto1.Registration)
if err := dec(in); err != nil {
@ -3153,6 +3309,24 @@ func _StorageAuthority_SerialExists_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _StorageAuthority_AddBlockedKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AddBlockedKeyRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(StorageAuthorityServer).AddBlockedKey(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/sa.StorageAuthority/AddBlockedKey",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(StorageAuthorityServer).AddBlockedKey(ctx, req.(*AddBlockedKeyRequest))
}
return interceptor(ctx, in, info, handler)
}
var _StorageAuthority_serviceDesc = grpc.ServiceDesc{
ServiceName: "sa.StorageAuthority",
HandlerType: (*StorageAuthorityServer)(nil),
@ -3233,6 +3407,10 @@ var _StorageAuthority_serviceDesc = grpc.ServiceDesc{
MethodName: "GetValidAuthorizations2",
Handler: _StorageAuthority_GetValidAuthorizations2_Handler,
},
{
MethodName: "KeyBlocked",
Handler: _StorageAuthority_KeyBlocked_Handler,
},
{
MethodName: "NewRegistration",
Handler: _StorageAuthority_NewRegistration_Handler,
@ -3301,6 +3479,10 @@ var _StorageAuthority_serviceDesc = grpc.ServiceDesc{
MethodName: "SerialExists",
Handler: _StorageAuthority_SerialExists_Handler,
},
{
MethodName: "AddBlockedKey",
Handler: _StorageAuthority_AddBlockedKey_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "sa/proto/sa.proto",

View File

@ -28,6 +28,7 @@ service StorageAuthority {
rpc GetValidOrderAuthorizations2(GetValidOrderAuthorizationsRequest) returns (Authorizations) {}
rpc CountInvalidAuthorizations2(CountInvalidAuthorizationsRequest) returns (Count) {}
rpc GetValidAuthorizations2(GetValidAuthorizationsRequest) returns (Authorizations) {}
rpc KeyBlocked(KeyBlockedRequest) returns (Exists) {}
// Adders
rpc NewRegistration(core.Registration) returns (core.Registration) {}
rpc UpdateRegistration(core.Registration) returns (core.Empty) {}
@ -46,6 +47,7 @@ service StorageAuthority {
rpc FinalizeAuthorization2(FinalizeAuthorizationRequest) returns (core.Empty) {}
rpc DeactivateAuthorization2(AuthorizationID2) returns (core.Empty) {}
rpc SerialExists(Serial) returns (Exists) {}
rpc AddBlockedKey(AddBlockedKeyRequest) returns (core.Empty) {}
}
message RegistrationID {
@ -242,3 +244,14 @@ message FinalizeAuthorizationRequest {
repeated core.ValidationRecord validationRecords = 5;
optional core.ProblemDetails validationError = 6;
}
message AddBlockedKeyRequest {
optional bytes keyHash = 1;
optional int64 added = 2; // Unix timestamp (nanoseconds)
optional string source = 3;
optional string comment = 4;
}
message KeyBlockedRequest {
optional bytes keyHash = 1;
}

View File

@ -1771,3 +1771,45 @@ func addKeyHash(db db.Inserter, cert *x509.Certificate) error {
}
return db.Insert(khm)
}
// AddBlockedKey adds a key hash to the blockedKeys table
func (ssa *SQLStorageAuthority) AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error) {
if req == nil || req.KeyHash == nil || req.Added == nil || req.Source == nil {
return nil, errIncompleteRequest
}
sourceInt, ok := stringToSourceInt[*req.Source]
if !ok {
return nil, errors.New("unknown source")
}
err := ssa.dbMap.Insert(&blockedKeyModel{
KeyHash: req.KeyHash,
Added: time.Unix(0, *req.Added),
Source: sourceInt,
Comment: req.Comment,
})
if err != nil {
if db.IsDuplicate(err) {
// Ignore duplicate inserts so multiple certs with the same key can
// be revoked.
return &corepb.Empty{}, nil
}
return nil, err
}
return &corepb.Empty{}, nil
}
// KeyBlocked checks if a key, indicated by a hash, is present in the blockedKeys table
func (ssa *SQLStorageAuthority) KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error) {
if req == nil || req.KeyHash == nil {
return nil, errIncompleteRequest
}
exists := false
if err := ssa.dbMap.SelectOne(&blockedKeyModel{}, `SELECT * FROM blockedKeys WHERE keyHash = ?`, req.KeyHash); err != nil {
if db.IsNoRows(err) {
return &sapb.Exists{Exists: &exists}, nil
}
return nil, err
}
exists = true
return &sapb.Exists{Exists: &exists}, nil
}

View File

@ -12,7 +12,9 @@ import (
"math/big"
"math/bits"
"net"
"os"
"reflect"
"strings"
"sync"
"testing"
"time"
@ -2247,3 +2249,75 @@ func TestSerialExists(t *testing.T) {
test.AssertNotError(t, err, "SerialExists failed")
test.AssertEquals(t, *resp.Exists, true)
}
func TestBlockedKey(t *testing.T) {
if !strings.HasSuffix(os.Getenv("BOULDER_CONFIG_DIR"), "config-next") {
return
}
sa, _, cleanUp := initSA(t)
defer cleanUp()
hashA := make([]byte, 32)
hashA[0] = 1
hashB := make([]byte, 32)
hashB[0] = 2
added := time.Now().UnixNano()
source := "API"
_, err := sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
KeyHash: hashA,
Added: &added,
Source: &source,
})
test.AssertNotError(t, err, "AddBlockedKey failed")
_, err = sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
KeyHash: hashA,
Added: &added,
Source: &source,
})
test.AssertNotError(t, err, "AddBlockedKey failed with duplicate insert")
comment := "testing comments"
_, err = sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
KeyHash: hashB,
Added: &added,
Source: &source,
Comment: &comment,
})
test.AssertNotError(t, err, "AddBlockedKey failed")
exists, err := sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
KeyHash: hashA,
})
test.AssertNotError(t, err, "KeyBlocked failed")
test.Assert(t, exists != nil, "*sapb.Exists is nil")
test.Assert(t, *exists.Exists, "KeyBlocked returned false for blocked key")
exists, err = sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
KeyHash: hashB,
})
test.AssertNotError(t, err, "KeyBlocked failed")
test.Assert(t, exists != nil, "*sapb.Exists is nil")
test.Assert(t, *exists.Exists, "KeyBlocked returned false for blocked key")
exists, err = sa.KeyBlocked(context.Background(), &sapb.KeyBlockedRequest{
KeyHash: []byte{5},
})
test.AssertNotError(t, err, "KeyBlocked failed")
test.Assert(t, exists != nil, "*sapb.Exists is nil")
test.Assert(t, !*exists.Exists, "KeyBlocked returned true for non-blocked key")
}
func TestAddBlockedKeyUnknownSource(t *testing.T) {
sa, _, cleanUp := initSA(t)
defer cleanUp()
added := int64(0)
source := "heyo"
_, err := sa.AddBlockedKey(context.Background(), &sapb.AddBlockedKeyRequest{
KeyHash: []byte{1, 2, 3},
Added: &added,
Source: &source,
})
test.AssertError(t, err, "AddBlockedKey didn't fail with unknown source")
test.AssertEquals(t, err.Error(), "unknown source")
}

View File

@ -137,7 +137,8 @@
"maxConcurrentRPCServerRequests": 100000,
"orphanQueueDir": "/tmp/orphaned-certificates-a",
"features": {
"StoreIssuerInfo": true
"StoreIssuerInfo": true,
"BlockedKeyTable": true
}
},

View File

@ -138,7 +138,8 @@
"maxConcurrentRPCServerRequests": 100000,
"orphanQueueDir": "/tmp/orphaned-certificates-b",
"features": {
"StoreIssuerInfo": true
"StoreIssuerInfo": true,
"BlockedKeyTable": true
}
},

View File

@ -46,6 +46,7 @@
]
},
"features": {
"BlockedKeyTable": true
},
"CTLogGroups2": [
{

View File

@ -39,7 +39,8 @@
}
},
"features": {
"StripDefaultSchemePort": true
"StripDefaultSchemePort": true,
"BlockedKeyTable": true
}
},

View File

@ -53,7 +53,8 @@
"features": {
"MandatoryPOSTAsGET": true,
"PrecertificateRevocation": true,
"StripDefaultSchemePort": true
"StripDefaultSchemePort": true,
"BlockedKeyTable": true
}
},

View File

@ -127,7 +127,7 @@ func TestPrecertificateRevocation(t *testing.T) {
tc.revokeClient.Account,
cert,
tc.revokeKey,
ocsp.KeyCompromise)
ocsp.Unspecified)
test.AssertNotError(t, err, "revoking precert")
// Check the OCSP response for the precertificate again. It should now be
@ -137,3 +137,33 @@ func TestPrecertificateRevocation(t *testing.T) {
})
}
}
func TestRevokeWithKeyCompromise(t *testing.T) {
t.Parallel()
if !strings.HasSuffix(os.Getenv("BOULDER_CONFIG_DIR"), "config-next") {
return
}
os.Setenv("DIRECTORY", "http://boulder:4001/directory")
c, err := makeClient("mailto:example@letsencrypt.org")
test.AssertNotError(t, err, "creating acme client")
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
test.AssertNotError(t, err, "failed to generate cert key")
res, err := authAndIssue(c, certKey, []string{random_domain()})
test.AssertNotError(t, err, "authAndIssue failed")
err = c.RevokeCertificate(
c.Account,
res.certs[0],
c.Account.PrivateKey,
ocsp.KeyCompromise,
)
test.AssertNotError(t, err, "failed to revoke certificate")
// attempt to create a new account using the blacklisted key
_, err = c.NewAccount(certKey, false, true)
test.AssertError(t, err, "NewAccount didn't fail with a blacklisted key")
test.AssertEquals(t, err.Error(), `acme: error code 400 "urn:ietf:params:acme:error:badPublicKey": public key is forbidden`)
}

View File

@ -30,6 +30,7 @@ GRANT SELECT,INSERT ON orderToAuthz2 TO 'sa'@'localhost';
GRANT INSERT,SELECT ON serials TO 'sa'@'localhost';
GRANT SELECT,INSERT ON precertificates TO 'sa'@'localhost';
GRANT SELECT,INSERT ON keyHashToSerial TO 'sa'@'localhost';
GRANT SELECT,INSERT ON blockedKeys TO 'sa'@'localhost';
-- OCSP Responder
GRANT SELECT ON certificateStatus TO 'ocsp_resp'@'localhost';

View File

@ -528,7 +528,7 @@ func (wfe *WebFrontEndImpl) verifyPOST(ctx context.Context, logEvent *web.Reques
// When looking up keys from the registrations DB, we can be confident they
// are "good". But when we are verifying against any submitted key, we want
// to check its quality before doing the verify.
if err = wfe.keyPolicy.GoodKey(submittedKey.Key); err != nil {
if err = wfe.keyPolicy.GoodKey(ctx, submittedKey.Key); err != nil {
wfe.joseErrorCounter.WithLabelValues("JWKRejectedByGoodKey").Inc()
return nil, nil, reg, probs.Malformed(err.Error())
}
@ -959,7 +959,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(ctx context.Context, logEvent *web.Re
// bytes on the wire, and (b) the CA logs all rejections as audit events, but
// a bad key from the client is just a malformed request and doesn't need to
// be audited.
if err := wfe.keyPolicy.GoodKey(certificateRequest.CSR.PublicKey); err != nil {
if err := wfe.keyPolicy.GoodKey(ctx, certificateRequest.CSR.PublicKey); err != nil {
wfe.sendError(response, logEvent, probs.Malformed("Invalid key in certificate request :: %s", err), err)
return
}

View File

@ -626,7 +626,7 @@ func (wfe *WebFrontEndImpl) validSelfAuthenticatedJWS(
}
// If the key doesn't meet the GoodKey policy return a problem immediately
if err := wfe.keyPolicy.GoodKey(pubKey.Key); err != nil {
if err := wfe.keyPolicy.GoodKey(ctx, pubKey.Key); err != nil {
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWKRejectedByGoodKey"}).Inc()
return nil, nil, probs.BadPublicKey(err.Error())
}
@ -689,6 +689,7 @@ type rolloverOperation struct {
// account) and that the account field of the rollover object matches the
// account that verified the outer JWS.
func (wfe *WebFrontEndImpl) validKeyRollover(
ctx context.Context,
outerJWS *jose.JSONWebSignature,
innerJWS *jose.JSONWebSignature,
oldKey *jose.JSONWebKey,
@ -701,7 +702,7 @@ func (wfe *WebFrontEndImpl) validKeyRollover(
}
// If the key doesn't meet the GoodKey policy return a problem immediately
if err := wfe.keyPolicy.GoodKey(jwk.Key); err != nil {
if err := wfe.keyPolicy.GoodKey(ctx, jwk.Key); err != nil {
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "KeyRolloverJWKRejectedByGoodKey"}).Inc()
return nil, probs.BadPublicKey(err.Error())
}

View File

@ -1789,7 +1789,7 @@ func (wfe *WebFrontEndImpl) KeyRollover(
}
// Validate the inner JWS as a key rollover request for the outer JWS
rolloverOperation, prob := wfe.validKeyRollover(outerJWS, innerJWS, oldKey, logEvent)
rolloverOperation, prob := wfe.validKeyRollover(ctx, outerJWS, innerJWS, oldKey, logEvent)
if prob != nil {
wfe.sendError(response, logEvent, prob, nil)
return