Skip to content

Commit 48cc211

Browse files
vault: validate encrypted value size in request validator (#21760)
* vault: validate encrypted value size in request validator (cherry picked from commit bcc73ae) * chore: trigger CI * chore: trigger CI
1 parent cceb6c3 commit 48cc211

4 files changed

Lines changed: 131 additions & 3 deletions

File tree

core/capabilities/vault/capability.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ func NewCapability(
412412
if err != nil {
413413
return nil, fmt.Errorf("could not create request batch size limiter: %w", err)
414414
}
415+
ciphertextLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.VaultCiphertextSizeLimit)
416+
if err != nil {
417+
return nil, fmt.Errorf("could not create ciphertext size limiter: %w", err)
418+
}
415419
return &Capability{
416420
lggr: logger.Named(lggr, "VaultCapability"),
417421
clock: clock,
@@ -420,6 +424,6 @@ func NewCapability(
420424
requestAuthorizer: requestAuthorizer,
421425
capabilitiesRegistry: capabilitiesRegistry,
422426
publicKey: publicKey,
423-
RequestValidator: NewRequestValidator(limiter),
427+
RequestValidator: NewRequestValidator(limiter, ciphertextLimiter),
424428
}, nil
425429
}

core/capabilities/vault/validator.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ import (
1111
"github.com/smartcontractkit/tdh2/go/tdh2/tdh2easy"
1212

1313
vaultcommon "github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/vault"
14+
pkgconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
1415
"github.com/smartcontractkit/chainlink-common/pkg/settings/limits"
1516
"github.com/smartcontractkit/chainlink/v2/core/capabilities/vault/vaulttypes"
1617
)
1718

1819
type RequestValidator struct {
1920
MaxRequestBatchSizeLimiter limits.BoundLimiter[int]
21+
MaxCiphertextLengthLimiter limits.BoundLimiter[pkgconfig.Size]
2022
}
2123

2224
func (r *RequestValidator) ValidateCreateSecretsRequest(publicKey *tdh2easy.PublicKey, request *vaultcommon.CreateSecretsRequest) error {
@@ -60,6 +62,9 @@ func (r *RequestValidator) validateWriteRequest(publicKey *tdh2easy.PublicKey, i
6062
if req.EncryptedValue == "" {
6163
return errors.New("secret must have encrypted value set at index " + strconv.Itoa(idx) + ":" + req.Id.String())
6264
}
65+
if err := r.validateCiphertextSize(req.EncryptedValue); err != nil {
66+
return fmt.Errorf("secret encrypted value at index %d is invalid: %w", idx, err)
67+
}
6368
err := EnsureRightLabelOnSecret(publicKey, req.EncryptedValue, req.Id.Owner)
6469
if err != nil {
6570
return errors.New("Encrypted Secret at index [" + strconv.Itoa(idx) + "] doesn't have owner as the label. Error: " + err.Error())
@@ -75,6 +80,21 @@ func (r *RequestValidator) validateWriteRequest(publicKey *tdh2easy.PublicKey, i
7580
return nil
7681
}
7782

83+
func (r *RequestValidator) validateCiphertextSize(encryptedValue string) error {
84+
rawCiphertext, err := hex.DecodeString(encryptedValue)
85+
if err != nil {
86+
return fmt.Errorf("failed to decode encrypted value: %w", err)
87+
}
88+
if err := r.MaxCiphertextLengthLimiter.Check(context.Background(), pkgconfig.Size(len(rawCiphertext))*pkgconfig.Byte); err != nil {
89+
var errBoundLimited limits.ErrorBoundLimited[pkgconfig.Size]
90+
if errors.As(err, &errBoundLimited) {
91+
return fmt.Errorf("ciphertext size exceeds maximum allowed size: %s", errBoundLimited.Limit)
92+
}
93+
return fmt.Errorf("failed to check ciphertext size limit: %w", err)
94+
}
95+
return nil
96+
}
97+
7898
func (r *RequestValidator) ValidateGetSecretsRequest(request *vaultcommon.GetSecretsRequest) error {
7999
if len(request.Requests) == 0 {
80100
return errors.New("no GetSecret request specified in request")
@@ -129,9 +149,13 @@ func (r *RequestValidator) ValidateDeleteSecretsRequest(request *vaultcommon.Del
129149
return nil
130150
}
131151

132-
func NewRequestValidator(maxRequestBatchSizeLimiter limits.BoundLimiter[int]) *RequestValidator {
152+
func NewRequestValidator(
153+
maxRequestBatchSizeLimiter limits.BoundLimiter[int],
154+
maxCiphertextLengthLimiter limits.BoundLimiter[pkgconfig.Size],
155+
) *RequestValidator {
133156
return &RequestValidator{
134157
MaxRequestBatchSizeLimiter: maxRequestBatchSizeLimiter,
158+
MaxCiphertextLengthLimiter: maxCiphertextLengthLimiter,
135159
}
136160
}
137161

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package vault
2+
3+
import (
4+
"encoding/hex"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
9+
vaultcommon "github.com/smartcontractkit/chainlink-common/pkg/capabilities/actions/vault"
10+
pkgconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
11+
"github.com/smartcontractkit/chainlink-common/pkg/settings/limits"
12+
)
13+
14+
func TestRequestValidator_CiphertextSizeLimit(t *testing.T) {
15+
validator := NewRequestValidator(
16+
limits.NewUpperBoundLimiter(10),
17+
limits.NewUpperBoundLimiter[pkgconfig.Size](10*pkgconfig.Byte),
18+
)
19+
20+
id := &vaultcommon.SecretIdentifier{
21+
Key: "key",
22+
Namespace: "namespace",
23+
Owner: "0x1111111111111111111111111111111111111111",
24+
}
25+
26+
tests := []struct {
27+
name string
28+
call func(*testing.T, *RequestValidator, string) error
29+
value string
30+
errSubstr string
31+
}{
32+
{
33+
name: "create accepts ciphertext at the limit",
34+
call: func(t *testing.T, validator *RequestValidator, value string) error {
35+
return validator.ValidateCreateSecretsRequest(nil, &vaultcommon.CreateSecretsRequest{
36+
RequestId: "request-id",
37+
EncryptedSecrets: []*vaultcommon.EncryptedSecret{
38+
{Id: id, EncryptedValue: value},
39+
},
40+
})
41+
},
42+
value: hex.EncodeToString(make([]byte, 10)),
43+
},
44+
{
45+
name: "create rejects ciphertext above the limit",
46+
call: func(t *testing.T, validator *RequestValidator, value string) error {
47+
return validator.ValidateCreateSecretsRequest(nil, &vaultcommon.CreateSecretsRequest{
48+
RequestId: "request-id",
49+
EncryptedSecrets: []*vaultcommon.EncryptedSecret{
50+
{Id: id, EncryptedValue: value},
51+
},
52+
})
53+
},
54+
value: hex.EncodeToString(make([]byte, 11)),
55+
errSubstr: "ciphertext size exceeds maximum allowed size",
56+
},
57+
{
58+
name: "update accepts ciphertext at the limit",
59+
call: func(t *testing.T, validator *RequestValidator, value string) error {
60+
return validator.ValidateUpdateSecretsRequest(nil, &vaultcommon.UpdateSecretsRequest{
61+
RequestId: "request-id",
62+
EncryptedSecrets: []*vaultcommon.EncryptedSecret{
63+
{Id: id, EncryptedValue: value},
64+
},
65+
})
66+
},
67+
value: hex.EncodeToString(make([]byte, 10)),
68+
},
69+
{
70+
name: "update rejects ciphertext above the limit",
71+
call: func(t *testing.T, validator *RequestValidator, value string) error {
72+
return validator.ValidateUpdateSecretsRequest(nil, &vaultcommon.UpdateSecretsRequest{
73+
RequestId: "request-id",
74+
EncryptedSecrets: []*vaultcommon.EncryptedSecret{
75+
{Id: id, EncryptedValue: value},
76+
},
77+
})
78+
},
79+
value: hex.EncodeToString(make([]byte, 11)),
80+
errSubstr: "ciphertext size exceeds maximum allowed size",
81+
},
82+
}
83+
84+
for _, tt := range tests {
85+
t.Run(tt.name, func(t *testing.T) {
86+
err := tt.call(t, validator, tt.value)
87+
if tt.errSubstr == "" {
88+
require.NoError(t, err)
89+
return
90+
}
91+
92+
require.Error(t, err)
93+
require.ErrorContains(t, err, tt.errSubstr)
94+
})
95+
}
96+
}

core/services/gateway/handlers/vault/handler.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,10 @@ func NewHandler(methodConfig json.RawMessage, donConfig *config.DONConfig, don g
197197
if err != nil {
198198
return nil, fmt.Errorf("could not create request batch size limiter: %w", err)
199199
}
200+
ciphertextLimiter, err := limits.MakeUpperBoundLimiter(limitsFactory, cresettings.Default.VaultCiphertextSizeLimit)
201+
if err != nil {
202+
return nil, fmt.Errorf("could not create ciphertext size limiter: %w", err)
203+
}
200204

201205
writeMethodsEnabled, err := limits.MakeGateLimiter(limitsFactory, cresettings.Default.GatewayVaultManagementEnabled)
202206
if err != nil {
@@ -218,7 +222,7 @@ func NewHandler(methodConfig json.RawMessage, donConfig *config.DONConfig, don g
218222
metrics: metrics,
219223
aggregator: &baseAggregator{capabilitiesRegistry: capabilitiesRegistry},
220224
clock: clock,
221-
RequestValidator: vaultcap.NewRequestValidator(limiter),
225+
RequestValidator: vaultcap.NewRequestValidator(limiter, ciphertextLimiter),
222226
}, nil
223227
}
224228

0 commit comments

Comments
 (0)