@@ -31,6 +31,23 @@ const (
3131
3232 // EpkBlinderNumBytes is the size of the EPK blinder.
3333 EpkBlinderNumBytes = 31
34+
35+ // MaxJwtSigLen is the maximum length of a JWT signature (DoS protection).
36+ // RSA-4096 signatures are 512 bytes; this allows room for future algorithms.
37+ MaxJwtSigLen = 1024
38+
39+ // MaxJwtPayloadLen is the maximum length of a JWT payload JSON (DoS protection).
40+ // Standard JWTs should be under 8KB.
41+ MaxJwtPayloadLen = 16384
42+
43+ // MaxUidKeyLen is the maximum length of a uid key string.
44+ MaxUidKeyLen = 128
45+
46+ // MaxAudValLen is the maximum length of an audience value override.
47+ MaxAudValLen = 512
48+
49+ // MaxIssValLen is the maximum length of an issuer value.
50+ MaxIssValLen = 200
3451)
3552
3653// Pepper is used to create a hiding identity commitment (IDC) when deriving a keyless address.
@@ -53,16 +70,26 @@ type IdCommitment struct {
5370}
5471
5572// NewIdCommitment creates a new identity commitment from bytes.
73+ // The input bytes are copied to prevent external mutation after construction.
5674func NewIdCommitment (bytes []byte ) (* IdCommitment , error ) {
5775 if len (bytes ) != IdCommitmentNumBytes {
5876 return nil , fmt .Errorf ("invalid identity commitment length: expected %d, got %d" , IdCommitmentNumBytes , len (bytes ))
5977 }
60- return & IdCommitment {inner : bytes }, nil
78+ // Defensively copy the input bytes so callers cannot mutate the commitment after construction
79+ inner := make ([]byte , IdCommitmentNumBytes )
80+ copy (inner , bytes )
81+ return & IdCommitment {inner : inner }, nil
6182}
6283
63- // Bytes returns the raw bytes of the identity commitment.
84+ // Bytes returns a copy of the raw bytes of the identity commitment.
85+ // The returned slice is a copy to prevent external mutation.
6486func (idc * IdCommitment ) Bytes () []byte {
65- return idc .inner
87+ if idc == nil || idc .inner == nil {
88+ return nil
89+ }
90+ out := make ([]byte , len (idc .inner ))
91+ copy (out , idc .inner )
92+ return out
6693}
6794
6895// MarshalBCS serializes the identity commitment to BCS.
@@ -155,7 +182,8 @@ func (key *KeylessPublicKey) MarshalBCS(ser *bcs.Serializer) {
155182
156183// UnmarshalBCS deserializes the keyless public key from BCS.
157184func (key * KeylessPublicKey ) UnmarshalBCS (des * bcs.Deserializer ) {
158- key .IssVal = des .ReadString ()
185+ // Use bounded read for issuer value (DoS protection)
186+ key .IssVal = des .ReadBoundedString (MaxIssValLen )
159187 if des .Error () != nil {
160188 return
161189 }
@@ -436,23 +464,26 @@ func (o *OpenIdSig) MarshalBCS(ser *bcs.Serializer) {
436464}
437465
438466// UnmarshalBCS deserializes the OpenIdSig from BCS.
467+ // Uses bounded reads to prevent DoS attacks from oversized payloads.
439468func (o * OpenIdSig ) UnmarshalBCS (des * bcs.Deserializer ) {
440- o .JwtSig = des .ReadBytes ()
469+ // Use bounded reads to validate size BEFORE allocation (DoS protection)
470+ o .JwtSig = des .ReadBoundedBytes (1 , MaxJwtSigLen )
441471 if des .Error () != nil {
442472 return
443473 }
444474
445- o .JwtPayloadJSON = des .ReadString ( )
475+ o .JwtPayloadJSON = des .ReadBoundedString ( MaxJwtPayloadLen )
446476 if des .Error () != nil {
447477 return
448478 }
449479
450- o .UidKey = des .ReadString ( )
480+ o .UidKey = des .ReadBoundedString ( MaxUidKeyLen )
451481 if des .Error () != nil {
452482 return
453483 }
454484
455- o .EpkBlinder = des .ReadBytes ()
485+ // EPK blinder has a fixed size
486+ o .EpkBlinder = des .ReadBoundedBytes (EpkBlinderNumBytes , EpkBlinderNumBytes )
456487 if des .Error () != nil {
457488 return
458489 }
@@ -464,7 +495,7 @@ func (o *OpenIdSig) UnmarshalBCS(des *bcs.Deserializer) {
464495
465496 // Optional idc_aud_val
466497 if des .Bool () {
467- s := des .ReadString ( )
498+ s := des .ReadBoundedString ( MaxAudValLen )
468499 o .IdcAudVal = & s
469500 }
470501}
0 commit comments