Remove deprecated WFE.RedeemNonceServices (#7493)

Fixes https://github.com/letsencrypt/boulder/issues/6610
This commit is contained in:
Aaron Gable 2024-05-21 10:13:13 -07:00 committed by GitHub
parent 4663b9898e
commit 5be3650e56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 95 additions and 360 deletions

View File

@ -66,23 +66,13 @@ type Config struct {
// used to lookup nonce-service instances used exclusively for nonce // used to lookup nonce-service instances used exclusively for nonce
// creation. In a multi-DC deployment this should refer to local // creation. In a multi-DC deployment this should refer to local
// nonce-service instances only. // nonce-service instances only.
GetNonceService *cmd.GRPCClientConfig GetNonceService *cmd.GRPCClientConfig `validate:"required"`
// RedeemNonceServices contains a map of nonce-service prefixes to
// gRPC configs we want to use to redeem nonces. In a multi-DC deployment
// this should contain all nonce-services from all DCs as we want to be
// able to redeem nonces generated at any DC.
//
// Deprecated: See RedeemNonceService, below.
// TODO (#6610) Remove this after all configs have migrated to
// `RedeemNonceService`.
RedeemNonceServices map[string]cmd.GRPCClientConfig `validate:"required_without=RedeemNonceService,omitempty,min=1,dive"`
// RedeemNonceService is a gRPC config which contains a list of SRV // RedeemNonceService is a gRPC config which contains a list of SRV
// names used to lookup nonce-service instances used exclusively for // names used to lookup nonce-service instances used exclusively for
// nonce redemption. In a multi-DC deployment this should contain both // nonce redemption. In a multi-DC deployment this should contain both
// local and remote nonce-service instances. // local and remote nonce-service instances.
RedeemNonceService *cmd.GRPCClientConfig `validate:"required_without=RedeemNonceServices"` RedeemNonceService *cmd.GRPCClientConfig `validate:"required"`
// NoncePrefixKey is a secret used for deriving the prefix of each nonce // NoncePrefixKey is a secret used for deriving the prefix of each nonce
// instance. It should contain 256 bits of random data to be suitable as // instance. It should contain 256 bits of random data to be suitable as
@ -209,7 +199,7 @@ func loadChain(certFiles []string) (*issuance.Certificate, []byte, error) {
return certs[0], buf.Bytes(), nil return certs[0], buf.Bytes(), nil
} }
func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.RegistrationAuthorityClient, sapb.StorageAuthorityReadOnlyClient, nonce.Getter, map[string]nonce.Redeemer, nonce.Redeemer, string) { func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.RegistrationAuthorityClient, sapb.StorageAuthorityReadOnlyClient, nonce.Getter, nonce.Redeemer, string) {
tlsConfig, err := c.WFE.TLS.Load(scope) tlsConfig, err := c.WFE.TLS.Load(scope)
cmd.FailOnError(err, "TLS config") cmd.FailOnError(err, "TLS config")
@ -221,15 +211,8 @@ func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.Regi
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA") cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to SA")
sac := sapb.NewStorageAuthorityReadOnlyClient(saConn) sac := sapb.NewStorageAuthorityReadOnlyClient(saConn)
// TODO(#6610) Refactor these checks. if c.WFE.RedeemNonceService == nil {
if c.WFE.RedeemNonceService != nil && c.WFE.RedeemNonceServices != nil { cmd.Fail("'redeemNonceService' must be configured.")
cmd.Fail("Only one of 'redeemNonceService' or 'redeemNonceServices' should be configured.")
}
if c.WFE.RedeemNonceService == nil && c.WFE.RedeemNonceServices == nil {
cmd.Fail("One of 'redeemNonceService' or 'redeemNonceServices' must be configured.")
}
if c.WFE.RedeemNonceService != nil && c.WFE.NoncePrefixKey.PasswordFile == "" {
cmd.Fail("'noncePrefixKey' must be configured if 'redeemNonceService' is configured.")
} }
if c.WFE.GetNonceService == nil { if c.WFE.GetNonceService == nil {
cmd.Fail("'getNonceService' must be configured") cmd.Fail("'getNonceService' must be configured")
@ -245,10 +228,6 @@ func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.Regi
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to get nonce service") cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to get nonce service")
gnc := nonce.NewGetter(getNonceConn) gnc := nonce.NewGetter(getNonceConn)
var rnc nonce.Redeemer
var npm map[string]nonce.Redeemer
if c.WFE.RedeemNonceService != nil {
// Dispatch nonce redemption RPCs dynamically.
if c.WFE.RedeemNonceService.SRVResolver != noncebalancer.SRVResolverScheme { if c.WFE.RedeemNonceService.SRVResolver != noncebalancer.SRVResolverScheme {
cmd.Fail(fmt.Sprintf( cmd.Fail(fmt.Sprintf(
"'redeemNonceService.SRVResolver' must be set to %q", noncebalancer.SRVResolverScheme), "'redeemNonceService.SRVResolver' must be set to %q", noncebalancer.SRVResolverScheme),
@ -256,21 +235,9 @@ func setupWFE(c Config, scope prometheus.Registerer, clk clock.Clock) (rapb.Regi
} }
redeemNonceConn, err := bgrpc.ClientSetup(c.WFE.RedeemNonceService, tlsConfig, scope, clk) redeemNonceConn, err := bgrpc.ClientSetup(c.WFE.RedeemNonceService, tlsConfig, scope, clk)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to redeem nonce service") cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to redeem nonce service")
rnc = nonce.NewRedeemer(redeemNonceConn) rnc := nonce.NewRedeemer(redeemNonceConn)
} else {
// Dispatch nonce redpemption RPCs using a static mapping.
//
// TODO(#6610) Remove code below and the `npm` mapping.
npm = make(map[string]nonce.Redeemer)
for prefix, serviceConfig := range c.WFE.RedeemNonceServices {
serviceConfig := serviceConfig
conn, err := bgrpc.ClientSetup(&serviceConfig, tlsConfig, scope, clk)
cmd.FailOnError(err, "Failed to load credentials and create gRPC connection to redeem nonce service")
npm[prefix] = nonce.NewRedeemer(conn)
}
}
return rac, sac, gnc, npm, rnc, rncKey return rac, sac, gnc, rnc, rncKey
} }
type errorWriter struct { type errorWriter struct {
@ -342,7 +309,7 @@ func main() {
clk := cmd.Clock() clk := cmd.Clock()
rac, sac, gnc, npm, rnc, npKey := setupWFE(c, stats, clk) rac, sac, gnc, rnc, npKey := setupWFE(c, stats, clk)
kp, err := sagoodkey.NewKeyPolicy(&c.WFE.GoodKey, sac.KeyBlocked) kp, err := sagoodkey.NewKeyPolicy(&c.WFE.GoodKey, sac.KeyBlocked)
cmd.FailOnError(err, "Unable to create key policy") cmd.FailOnError(err, "Unable to create key policy")
@ -408,7 +375,6 @@ func main() {
rac, rac,
sac, sac,
gnc, gnc,
npm,
rnc, rnc,
npKey, npKey,
accountGetter, accountGetter,

View File

@ -18,29 +18,22 @@ type Config struct {
cmd.ServiceConfig cmd.ServiceConfig
MaxUsed int MaxUsed int
// TODO(#6610): Remove once we've moved to derivable prefixes by
// default.
NoncePrefix string `validate:"excluded_with=UseDerivablePrefix,omitempty,len=4"`
// UseDerivablePrefix indicates whether to use a nonce prefix derived // UseDerivablePrefix indicates whether to use a nonce prefix derived
// from the gRPC listening address. If this is false, the nonce prefix // from the gRPC listening address. If this is false, the nonce prefix
// will be the value of the NoncePrefix field. If this is true, the // will be the value of the NoncePrefix field. If this is true, the
// NoncePrefixKey field is required. // NoncePrefixKey field is required.
// TODO(#6610): Remove this.
// //
// TODO(#6610): Remove once we've moved to derivable prefixes by // Deprecated: this value is ignored, and treated as though it is always true.
// default. UseDerivablePrefix bool `validate:"-"`
UseDerivablePrefix bool `validate:"excluded_with=NoncePrefix"`
// NoncePrefixKey is a secret used for deriving the prefix of each nonce // NoncePrefixKey is a secret used for deriving the prefix of each nonce
// instance. It should contain 256 bits (32 bytes) of random data to be // instance. It should contain 256 bits (32 bytes) of random data to be
// suitable as an HMAC-SHA256 key (e.g. the output of `openssl rand -hex // suitable as an HMAC-SHA256 key (e.g. the output of `openssl rand -hex
// 32`). In a multi-DC deployment this value should be the same across // 32`). In a multi-DC deployment this value should be the same across
// all boulder-wfe and nonce-service instances. This is only used if // all boulder-wfe and nonce-service instances.
// UseDerivablePrefix is true. NoncePrefixKey cmd.PasswordConfig `validate:"required"`
//
// TODO(#6610): Edit this comment once we've moved to derivable prefixes
// by default.
NoncePrefixKey cmd.PasswordConfig `validate:"excluded_with=NoncePrefix,structonly"`
Syslog cmd.SyslogConfig Syslog cmd.SyslogConfig
OpenTelemetry cmd.OpenTelemetryConfig OpenTelemetry cmd.OpenTelemetryConfig
@ -89,28 +82,20 @@ func main() {
c.NonceService.DebugAddr = *debugAddr c.NonceService.DebugAddr = *debugAddr
} }
// TODO(#6610): Remove once we've moved to derivable prefixes by default. if c.NonceService.NoncePrefixKey.PasswordFile == "" {
if c.NonceService.NoncePrefix != "" && c.NonceService.UseDerivablePrefix { cmd.Fail("NoncePrefixKey PasswordFile must be set")
cmd.Fail("Cannot set both 'noncePrefix' and 'useDerivablePrefix'")
} }
// TODO(#6610): Remove once we've moved to derivable prefixes by default.
if c.NonceService.UseDerivablePrefix && c.NonceService.NoncePrefixKey.PasswordFile == "" {
cmd.Fail("Cannot set 'noncePrefixKey' without 'useDerivablePrefix'")
}
if c.NonceService.UseDerivablePrefix && c.NonceService.NoncePrefixKey.PasswordFile != "" {
key, err := c.NonceService.NoncePrefixKey.Pass() key, err := c.NonceService.NoncePrefixKey.Pass()
cmd.FailOnError(err, "Failed to load 'noncePrefixKey' file.") cmd.FailOnError(err, "Failed to load 'noncePrefixKey' file.")
c.NonceService.NoncePrefix, err = derivePrefix(key, c.NonceService.GRPC.Address) noncePrefix, err := derivePrefix(key, c.NonceService.GRPC.Address)
cmd.FailOnError(err, "Failed to derive nonce prefix") cmd.FailOnError(err, "Failed to derive nonce prefix")
}
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.NonceService.Syslog, c.NonceService.OpenTelemetry, c.NonceService.DebugAddr) scope, logger, oTelShutdown := cmd.StatsAndLogging(c.NonceService.Syslog, c.NonceService.OpenTelemetry, c.NonceService.DebugAddr)
defer oTelShutdown(context.Background()) defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString()) logger.Info(cmd.VersionString())
ns, err := nonce.NewNonceService(scope, c.NonceService.MaxUsed, c.NonceService.NoncePrefix) ns, err := nonce.NewNonceService(scope, c.NonceService.MaxUsed, noncePrefix)
cmd.FailOnError(err, "Failed to initialize nonce service") cmd.FailOnError(err, "Failed to initialize nonce service")
tlsConfig, err := c.NonceService.TLS.Load(scope) tlsConfig, err := c.NonceService.TLS.Load(scope)

View File

@ -39,12 +39,6 @@ const (
// PrefixLen is the character length of a nonce prefix. // PrefixLen is the character length of a nonce prefix.
PrefixLen = 8 PrefixLen = 8
// DeprecatedPrefixLen is the character length of a nonce prefix.
//
// Deprecated: Use PrefixLen instead.
// TODO(#6610): Remove once we've moved to derivable prefixes by default.
DeprecatedPrefixLen = 4
// NonceLen is the character length of a nonce, excluding the prefix. // NonceLen is the character length of a nonce, excluding the prefix.
NonceLen = 32 NonceLen = 32
defaultMaxUsed = 65536 defaultMaxUsed = 65536
@ -81,9 +75,6 @@ type NonceService struct {
nonceEarliest prometheus.Gauge nonceEarliest prometheus.Gauge
nonceRedeems *prometheus.CounterVec nonceRedeems *prometheus.CounterVec
nonceHeapLatency prometheus.Histogram nonceHeapLatency prometheus.Histogram
// TODO(#6610): Remove this field once we've moved to derivable prefixes by
// default.
prefixLen int
} }
type int64Heap []int64 type int64Heap []int64
@ -106,23 +97,16 @@ func (h *int64Heap) Pop() interface{} {
// NewNonceService constructs a NonceService with defaults // NewNonceService constructs a NonceService with defaults
func NewNonceService(stats prometheus.Registerer, maxUsed int, prefix string) (*NonceService, error) { func NewNonceService(stats prometheus.Registerer, maxUsed int, prefix string) (*NonceService, error) {
// If a prefix is provided it must be four characters and valid base64. The // If a prefix is provided it must be eight characters and valid base64. The
// prefix is required to be base64url as RFC8555 section 6.5.1 requires that // prefix is required to be base64url as RFC8555 section 6.5.1 requires that
// nonces use that encoding. As base64 operates on three byte binary // nonces use that encoding. As base64 operates on three byte binary segments
// segments we require the prefix to be three or six bytes (four or eight // we require the prefix to be six bytes (eight characters) so that the bytes
// characters) so that the bytes preceding the prefix wouldn't impact the // preceding the prefix wouldn't impact the encoding.
// encoding.
//
// TODO(#6610): Update this comment once we've moved to eight character
// prefixes by default.
if prefix != "" { if prefix != "" {
// TODO(#6610): Refactor once we've moved to derivable prefixes by if len(prefix) != PrefixLen {
// default.
if len(prefix) != PrefixLen && len(prefix) != DeprecatedPrefixLen {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"'noncePrefix' must be %d or %d characters, not %d", "nonce prefix must be %d characters, not %d",
PrefixLen, PrefixLen,
DeprecatedPrefixLen,
len(prefix), len(prefix),
) )
} }
@ -182,9 +166,6 @@ func NewNonceService(stats prometheus.Registerer, maxUsed int, prefix string) (*
nonceEarliest: nonceEarliest, nonceEarliest: nonceEarliest,
nonceRedeems: nonceRedeems, nonceRedeems: nonceRedeems,
nonceHeapLatency: nonceHeapLatency, nonceHeapLatency: nonceHeapLatency,
// TODO(#6610): Remove this field once we've moved to derivable prefixes
// by default.
prefixLen: len(prefix),
}, nil }, nil
} }
@ -303,43 +284,10 @@ func (ns *NonceService) Valid(nonce string) bool {
// splitNonce splits a nonce into a prefix and a body. // splitNonce splits a nonce into a prefix and a body.
func (ns *NonceService) splitNonce(nonce string) (string, string, error) { func (ns *NonceService) splitNonce(nonce string) (string, string, error) {
if len(nonce) < ns.prefixLen { if len(nonce) < PrefixLen {
return "", "", errInvalidNonceLength return "", "", errInvalidNonceLength
} }
return nonce[:ns.prefixLen], nonce[ns.prefixLen:], nil return nonce[:PrefixLen], nonce[PrefixLen:], nil
}
// splitDeprecatedNonce splits a nonce into a prefix and a body.
//
// Deprecated: Use NonceService.splitDeprecatedNonce instead.
// TODO(#6610): Remove this function once we've moved to derivable prefixes by
// default.
func splitDeprecatedNonce(nonce string) (string, string, error) {
if len(nonce) < DeprecatedPrefixLen {
return "", "", errInvalidNonceLength
}
return nonce[:DeprecatedPrefixLen], nonce[DeprecatedPrefixLen:], nil
}
// RemoteRedeem checks the nonce prefix and routes the Redeem RPC
// to the associated remote nonce service.
//
// TODO(#6610): Remove this function once we've moved to derivable prefixes by
// default.
func RemoteRedeem(ctx context.Context, noncePrefixMap map[string]Redeemer, nonce string) (bool, error) {
prefix, _, err := splitDeprecatedNonce(nonce)
if err != nil {
return false, nil
}
nonceService, present := noncePrefixMap[prefix]
if !present {
return false, nil
}
resp, err := nonceService.Redeem(ctx, &noncepb.NonceMessage{Nonce: nonce})
if err != nil {
return false, err
}
return resp.Valid, nil
} }
// NewServer returns a new Server, wrapping a NonceService. // NewServer returns a new Server, wrapping a NonceService.

View File

@ -1,13 +1,9 @@
package nonce package nonce
import ( import (
"context"
"errors"
"fmt" "fmt"
"testing" "testing"
"google.golang.org/grpc"
"github.com/letsencrypt/boulder/metrics" "github.com/letsencrypt/boulder/metrics"
noncepb "github.com/letsencrypt/boulder/nonce/proto" noncepb "github.com/letsencrypt/boulder/nonce/proto"
"github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test"
@ -129,7 +125,7 @@ func BenchmarkNonces(b *testing.B) {
} }
func TestNoncePrefixing(t *testing.T) { func TestNoncePrefixing(t *testing.T) {
ns, err := NewNonceService(metrics.NoopRegisterer, 0, "zinc") ns, err := NewNonceService(metrics.NoopRegisterer, 0, "aluminum")
test.AssertNotError(t, err, "Could not create nonce service") test.AssertNotError(t, err, "Could not create nonce service")
n, err := ns.Nonce() n, err := ns.Nonce()
@ -146,66 +142,12 @@ func TestNoncePrefixing(t *testing.T) {
test.Assert(t, !ns.Valid(n[6:]), "Valid nonce without prefix accepted") test.Assert(t, !ns.Valid(n[6:]), "Valid nonce without prefix accepted")
} }
type validRedeemer struct{}
func (vr *validRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
return &noncepb.ValidMessage{Valid: true}, nil
}
type invalidRedeemer struct{}
func (ivr *invalidRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
return &noncepb.ValidMessage{Valid: false}, nil
}
type brokenRedeemer struct{}
func (br *brokenRedeemer) Redeem(ctx context.Context, in *noncepb.NonceMessage, _ ...grpc.CallOption) (*noncepb.ValidMessage, error) {
return nil, errors.New("broken redeemer!")
}
func TestRemoteRedeem(t *testing.T) {
valid, err := RemoteRedeem(context.Background(), nil, "q")
test.AssertNotError(t, err, "RemoteRedeem failed")
test.Assert(t, !valid, "RemoteRedeem accepted an invalid nonce")
valid, err = RemoteRedeem(context.Background(), nil, "")
test.AssertNotError(t, err, "RemoteRedeem failed")
test.Assert(t, !valid, "RemoteRedeem accepted an empty nonce")
prefixMap := map[string]Redeemer{
"abcd": &brokenRedeemer{},
"wxyz": &invalidRedeemer{},
}
// Attempt to redeem a nonce with a prefix not in the prefix map, expect return false, nil
valid, err = RemoteRedeem(context.Background(), prefixMap, "asddCQEC")
test.AssertNotError(t, err, "RemoteRedeem failed")
test.Assert(t, !valid, "RemoteRedeem accepted nonce not in prefix map")
// Attempt to redeem a nonce with a prefix in the prefix map, remote returns error
// expect false, err
_, err = RemoteRedeem(context.Background(), prefixMap, "abcdbeef")
test.AssertError(t, err, "RemoteRedeem didn't return error when remote did")
// Attempt to redeem a nonce with a prefix in the prefix map, remote returns invalid
// expect false, nil
valid, err = RemoteRedeem(context.Background(), prefixMap, "wxyzdead")
test.AssertNotError(t, err, "RemoteRedeem failed")
test.Assert(t, !valid, "RemoteRedeem didn't honor remote result")
// Attempt to redeem a nonce with a prefix in the prefix map, remote returns valid
// expect true, nil
prefixMap["wxyz"] = &validRedeemer{}
valid, err = RemoteRedeem(context.Background(), prefixMap, "wxyzdead")
test.AssertNotError(t, err, "RemoteRedeem failed")
test.Assert(t, valid, "RemoteRedeem didn't honor remote result")
}
func TestNoncePrefixValidation(t *testing.T) { func TestNoncePrefixValidation(t *testing.T) {
_, err := NewNonceService(metrics.NoopRegisterer, 0, "hey") _, err := NewNonceService(metrics.NoopRegisterer, 0, "whatsup")
test.AssertError(t, err, "NewNonceService didn't fail with short prefix") test.AssertError(t, err, "NewNonceService didn't fail with short prefix")
_, err = NewNonceService(metrics.NoopRegisterer, 0, "hey!") _, err = NewNonceService(metrics.NoopRegisterer, 0, "whatsup!")
test.AssertError(t, err, "NewNonceService didn't fail with invalid base64") test.AssertError(t, err, "NewNonceService didn't fail with invalid base64")
_, err = NewNonceService(metrics.NoopRegisterer, 0, "heyy") _, err = NewNonceService(metrics.NoopRegisterer, 0, "whatsupp")
test.AssertNotError(t, err, "NewNonceService failed with valid nonce prefix") test.AssertNotError(t, err, "NewNonceService failed with valid nonce prefix")
} }

View File

@ -1,7 +1,6 @@
{ {
"NonceService": { "NonceService": {
"maxUsed": 131072, "maxUsed": 131072,
"useDerivablePrefix": true,
"noncePrefixKey": { "noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key" "passwordFile": "test/secrets/nonce_prefix_key"
}, },

View File

@ -1,7 +1,6 @@
{ {
"NonceService": { "NonceService": {
"maxUsed": 131072, "maxUsed": 131072,
"useDerivablePrefix": true,
"noncePrefixKey": { "noncePrefixKey": {
"passwordFile": "test/secrets/nonce_prefix_key" "passwordFile": "test/secrets/nonce_prefix_key"
}, },

View File

@ -224,10 +224,7 @@ func (wfe *WebFrontEndImpl) validNonce(ctx context.Context, header jose.Header)
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSMissingNonce"}).Inc() wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSMissingNonce"}).Inc()
return probs.BadNonce("JWS has no anti-replay nonce") return probs.BadNonce("JWS has no anti-replay nonce")
} }
var valid bool
var err error
if wfe.noncePrefixMap == nil {
// Dispatch nonce redemption RPCs dynamically.
prob := nonceWellFormed(header.Nonce, nonce.PrefixLen) prob := nonceWellFormed(header.Nonce, nonce.PrefixLen)
if prob != nil { if prob != nil {
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSMalformedNonce"}).Inc() wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSMalformedNonce"}).Inc()
@ -254,23 +251,8 @@ func (wfe *WebFrontEndImpl) validNonce(ctx context.Context, header jose.Header)
resp = &noncepb.ValidMessage{Valid: false} resp = &noncepb.ValidMessage{Valid: false}
wfe.stats.nonceNoMatchingBackendCount.Inc() wfe.stats.nonceNoMatchingBackendCount.Inc()
} }
valid = resp.Valid
} else {
// Dispatch nonce redpemption RPCs using a static mapping.
//
// TODO(#6610) Remove code below and the `npm` mapping.
prob := nonceWellFormed(header.Nonce, nonce.DeprecatedPrefixLen)
if prob != nil {
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSMalformedNonce"}).Inc()
return prob
}
valid, err = nonce.RemoteRedeem(ctx, wfe.noncePrefixMap, header.Nonce) if !resp.Valid {
if err != nil {
return web.ProblemDetailsForError(err, "failed to redeem nonce")
}
}
if !valid {
wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSInvalidNonce"}).Inc() wfe.stats.joseErrorCount.With(prometheus.Labels{"type": "JWSInvalidNonce"}).Inc()
return probs.BadNonce(fmt.Sprintf("JWS has an invalid anti-replay nonce: %q", header.Nonce)) return probs.BadNonce(fmt.Sprintf("JWS has an invalid anti-replay nonce: %q", header.Nonce))
} }

View File

@ -9,7 +9,6 @@ import (
"crypto/rsa" "crypto/rsa"
"fmt" "fmt"
"net/http" "net/http"
"os"
"strings" "strings"
"testing" "testing"
@ -691,10 +690,6 @@ func (b badNonceProvider) Nonce() (string, error) {
// characters and static prefixes are 4 characters. // characters and static prefixes are 4 characters.
return "woww", nil return "woww", nil
} }
if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
// TODO(#6610): Remove this.
return "mlol3ov77I5Ui-cdaY_k8IcjK58FvbG0y_BCRrx5rGQ8rjA", nil
}
return "mlolmlol3ov77I5Ui-cdaY_k8IcjK58FvbG0y_BCRrx5rGQ8rjA", nil return "mlolmlol3ov77I5Ui-cdaY_k8IcjK58FvbG0y_BCRrx5rGQ8rjA", nil
} }
@ -708,10 +703,6 @@ func TestValidNonce(t *testing.T) {
JWS *jose.JSONWebSignature JWS *jose.JSONWebSignature
ExpectedResult *probs.ProblemDetails ExpectedResult *probs.ProblemDetails
ErrorStatType string ErrorStatType string
// TODO(#6610): Remove this.
SkipConfigNext bool
// TODO(#6610): Remove this.
SkipConfig bool
}{ }{
{ {
Name: "No nonce in JWS", Name: "No nonce in JWS",
@ -743,17 +734,6 @@ func TestValidNonce(t *testing.T) {
}, },
ErrorStatType: "JWSMalformedNonce", ErrorStatType: "JWSMalformedNonce",
}, },
{
Name: "Invalid nonce in JWS (test/config)",
JWS: signer.invalidNonce(),
ExpectedResult: &probs.ProblemDetails{
Type: probs.BadNonceProblem,
Detail: "JWS has an invalid anti-replay nonce: \"mlol3ov77I5Ui-cdaY_k8IcjK58FvbG0y_BCRrx5rGQ8rjA\"",
HTTPStatus: http.StatusBadRequest,
},
ErrorStatType: "JWSInvalidNonce",
SkipConfigNext: true,
},
{ {
Name: "Invalid nonce in JWS (test/config-next)", Name: "Invalid nonce in JWS (test/config-next)",
JWS: signer.invalidNonce(), JWS: signer.invalidNonce(),
@ -763,7 +743,6 @@ func TestValidNonce(t *testing.T) {
HTTPStatus: http.StatusBadRequest, HTTPStatus: http.StatusBadRequest,
}, },
ErrorStatType: "JWSInvalidNonce", ErrorStatType: "JWSInvalidNonce",
SkipConfig: true,
}, },
{ {
Name: "Valid nonce in JWS", Name: "Valid nonce in JWS",
@ -774,14 +753,6 @@ func TestValidNonce(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.Name, func(t *testing.T) {
// TODO(#6610): Remove this.
if os.Getenv("BOULDER_CONFIG_DIR") == "test/config-next" {
if tc.SkipConfigNext {
t.Skip("Skipping test in config-next")
}
} else if tc.SkipConfig {
t.Skip("Skipping test in config")
}
wfe.stats.joseErrorCount.Reset() wfe.stats.joseErrorCount.Reset()
prob := wfe.validNonce(context.Background(), tc.JWS.Signatures[0].Header) prob := wfe.validNonce(context.Background(), tc.JWS.Signatures[0].Header)
if tc.ExpectedResult == nil && prob != nil { if tc.ExpectedResult == nil && prob != nil {
@ -806,10 +777,6 @@ func (n noBackendsNonceRedeemer) Redeem(ctx context.Context, _ *noncepb.NonceMes
} }
func TestValidNonce_NoMatchingBackendFound(t *testing.T) { func TestValidNonce_NoMatchingBackendFound(t *testing.T) {
// TODO(#6610): Remove this.
if os.Getenv("BOULDER_CONFIG_DIR") != "test/config-next" {
t.Skip("Skipping test in config")
}
wfe, _, signer := setupWFE(t) wfe, _, signer := setupWFE(t)
goodJWS, _, _ := signer.embeddedJWK(nil, "", "") goodJWS, _, _ := signer.embeddedJWK(nil, "", "")
wfe.rnc = noBackendsNonceRedeemer{} wfe.rnc = noBackendsNonceRedeemer{}
@ -1364,10 +1331,6 @@ func TestValidJWSForKey(t *testing.T) {
Body string Body string
ExpectedProblem *probs.ProblemDetails ExpectedProblem *probs.ProblemDetails
ErrorStatType string ErrorStatType string
// TODO(#6610): Remove this.
SkipConfig bool
// TODO(#6610): Remove this.
SkipConfigNext bool
}{ }{
{ {
Name: "JWS with an invalid algorithm", Name: "JWS with an invalid algorithm",
@ -1380,18 +1343,6 @@ func TestValidJWSForKey(t *testing.T) {
}, },
ErrorStatType: "JWSAlgorithmCheckFailed", ErrorStatType: "JWSAlgorithmCheckFailed",
}, },
{
Name: "JWS with an invalid nonce (test/config)",
JWS: bJSONWebSignature{signer.invalidNonce()},
JWK: goodJWK,
ExpectedProblem: &probs.ProblemDetails{
Type: probs.BadNonceProblem,
Detail: "JWS has an invalid anti-replay nonce: \"mlol3ov77I5Ui-cdaY_k8IcjK58FvbG0y_BCRrx5rGQ8rjA\"",
HTTPStatus: http.StatusBadRequest,
},
ErrorStatType: "JWSInvalidNonce",
SkipConfigNext: true,
},
{ {
Name: "JWS with an invalid nonce (test/config-next)", Name: "JWS with an invalid nonce (test/config-next)",
JWS: bJSONWebSignature{signer.invalidNonce()}, JWS: bJSONWebSignature{signer.invalidNonce()},
@ -1402,7 +1353,6 @@ func TestValidJWSForKey(t *testing.T) {
HTTPStatus: http.StatusBadRequest, HTTPStatus: http.StatusBadRequest,
}, },
ErrorStatType: "JWSInvalidNonce", ErrorStatType: "JWSInvalidNonce",
SkipConfig: true,
}, },
{ {
Name: "JWS with broken signature", Name: "JWS with broken signature",
@ -1445,16 +1395,7 @@ func TestValidJWSForKey(t *testing.T) {
} }
for _, tc := range testCases { for _, tc := range testCases {
// TODO(#6610): Remove this.
t.Run(tc.Name, func(t *testing.T) { t.Run(tc.Name, func(t *testing.T) {
// TODO(#6610): Remove this.
if os.Getenv("BOULDER_CONFIG_DIR") == "test/config-next" {
if tc.SkipConfigNext {
t.Skip("Skipping test in config-next")
}
} else if tc.SkipConfig {
t.Skip("Skipping test in config")
}
wfe.stats.joseErrorCount.Reset() wfe.stats.joseErrorCount.Reset()
request := makePostRequestWithPath("test", tc.Body) request := makePostRequestWithPath("test", tc.Body)
outPayload, prob := wfe.validJWSForKey(context.Background(), &tc.JWS, tc.JWK, request) outPayload, prob := wfe.validJWSForKey(context.Background(), &tc.JWS, tc.JWK, request)

View File

@ -97,10 +97,6 @@ type WebFrontEndImpl struct {
// nonces. It's configured to route requests to backends colocated with the // nonces. It's configured to route requests to backends colocated with the
// WFE. // WFE.
gnc nonce.Getter gnc nonce.Getter
// Register of anti-replay nonces
//
// Deprecated: See `rnc`, above.
noncePrefixMap map[string]nonce.Redeemer
// rnc is a nonce-service client used exclusively for the redemption of // rnc is a nonce-service client used exclusively for the redemption of
// nonces. It uses a custom RPC load balancer which is configured to route // nonces. It uses a custom RPC load balancer which is configured to route
// requests to backends based on the prefix and HMAC key passed as in the // requests to backends based on the prefix and HMAC key passed as in the
@ -189,7 +185,6 @@ func NewWebFrontEndImpl(
rac rapb.RegistrationAuthorityClient, rac rapb.RegistrationAuthorityClient,
sac sapb.StorageAuthorityReadOnlyClient, sac sapb.StorageAuthorityReadOnlyClient,
gnc nonce.Getter, gnc nonce.Getter,
noncePrefixMap map[string]nonce.Redeemer,
rnc nonce.Redeemer, rnc nonce.Redeemer,
rncKey string, rncKey string,
accountGetter AccountGetter, accountGetter AccountGetter,
@ -210,8 +205,7 @@ func NewWebFrontEndImpl(
return WebFrontEndImpl{}, errors.New("must provide a service for nonce issuance") return WebFrontEndImpl{}, errors.New("must provide a service for nonce issuance")
} }
// TODO(#6610): Remove the check for the map. if rnc == nil {
if noncePrefixMap == nil && rnc == nil {
return WebFrontEndImpl{}, errors.New("must provide a service for nonce redemption") return WebFrontEndImpl{}, errors.New("must provide a service for nonce redemption")
} }
@ -229,7 +223,6 @@ func NewWebFrontEndImpl(
ra: rac, ra: rac,
sa: sac, sa: sac,
gnc: gnc, gnc: gnc,
noncePrefixMap: noncePrefixMap,
rnc: rnc, rnc: rnc,
rncKey: rncKey, rncKey: rncKey,
accountGetter: accountGetter, accountGetter: accountGetter,

View File

@ -349,22 +349,14 @@ func setupWFE(t *testing.T) (WebFrontEndImpl, clock.FakeClock, requestSigner) {
log := blog.NewMock() log := blog.NewMock()
var gnc nonce.Getter
var noncePrefixMap map[string]nonce.Redeemer
var rnc nonce.Redeemer
var rncKey string
var inmemNonceService *inmemnonce.Service
var limiter *ratelimits.Limiter
var txnBuilder *ratelimits.TransactionBuilder
if strings.Contains(os.Getenv("BOULDER_CONFIG_DIR"), "test/config-next") {
// Use derived nonces. // Use derived nonces.
noncePrefix := nonce.DerivePrefix("192.168.1.1:8080", "b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f") noncePrefix := nonce.DerivePrefix("192.168.1.1:8080", "b8c758dd85e113ea340ce0b3a99f389d40a308548af94d1730a7692c1874f1f")
nonceService, err := nonce.NewNonceService(metrics.NoopRegisterer, 100, noncePrefix) nonceService, err := nonce.NewNonceService(metrics.NoopRegisterer, 100, noncePrefix)
test.AssertNotError(t, err, "making nonceService") test.AssertNotError(t, err, "making nonceService")
inmemNonceService = &inmemnonce.Service{NonceService: nonceService} inmemNonceService := &inmemnonce.Service{NonceService: nonceService}
gnc = inmemNonceService gnc := inmemNonceService
rnc = inmemNonceService rnc := inmemNonceService
// Setup rate limiting. // Setup rate limiting.
rc := bredis.Config{ rc := bredis.Config{
@ -389,21 +381,10 @@ func setupWFE(t *testing.T) (WebFrontEndImpl, clock.FakeClock, requestSigner) {
test.AssertNotError(t, err, "making redis ring client") test.AssertNotError(t, err, "making redis ring client")
source := ratelimits.NewRedisSource(ring.Ring, fc, stats) source := ratelimits.NewRedisSource(ring.Ring, fc, stats)
test.AssertNotNil(t, source, "source should not be nil") test.AssertNotNil(t, source, "source should not be nil")
limiter, err = ratelimits.NewLimiter(fc, source, stats) limiter, err := ratelimits.NewLimiter(fc, source, stats)
test.AssertNotError(t, err, "making limiter") test.AssertNotError(t, err, "making limiter")
txnBuilder, err = ratelimits.NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "") txnBuilder, err := ratelimits.NewTransactionBuilder("../test/config-next/wfe2-ratelimit-defaults.yml", "")
test.AssertNotError(t, err, "making transaction composer") test.AssertNotError(t, err, "making transaction composer")
} else {
// TODO(#6610): Remove this once we've moved to derived to prefixes.
noncePrefix := "mlem"
nonceService, err := nonce.NewNonceService(metrics.NoopRegisterer, 100, noncePrefix)
test.AssertNotError(t, err, "making nonceService")
inmemNonceService = &inmemnonce.Service{NonceService: nonceService}
gnc = inmemNonceService
noncePrefixMap = map[string]nonce.Redeemer{noncePrefix: inmemNonceService}
rnc = inmemNonceService
}
wfe, err := NewWebFrontEndImpl( wfe, err := NewWebFrontEndImpl(
stats, stats,
@ -419,9 +400,8 @@ func setupWFE(t *testing.T) (WebFrontEndImpl, clock.FakeClock, requestSigner) {
&MockRegistrationAuthority{}, &MockRegistrationAuthority{},
mockSA, mockSA,
gnc, gnc,
noncePrefixMap,
rnc, rnc,
rncKey, "rncKey",
mockSA, mockSA,
limiter, limiter,
txnBuilder, txnBuilder,