From 022893dbc942b84f2c153380ebddaafc1a000021 Mon Sep 17 00:00:00 2001 From: Dmitry Bilienko Date: Thu, 13 Apr 2023 15:19:58 +0500 Subject: [PATCH] Additional validation of identifiers and new unit tests. --- commonspace/spacestorage/spacestorage.go | 54 ++- commonspace/spacestorage/spacestorage_test.go | 329 +++++++++++++----- 2 files changed, 288 insertions(+), 95 deletions(-) diff --git a/commonspace/spacestorage/spacestorage.go b/commonspace/spacestorage/spacestorage.go index af4ab7e5..82961cba 100644 --- a/commonspace/spacestorage/spacestorage.go +++ b/commonspace/spacestorage/spacestorage.go @@ -2,7 +2,6 @@ package spacestorage import ( - "bytes" "context" "errors" "fmt" @@ -73,16 +72,24 @@ func ValidateSpaceStorageCreatePayload(payload SpaceStorageCreatePayload) (err e if err != nil { return } - err = validateCreateSpaceAclPayload(payload.AclWithId) + aclSpaceId, err := validateCreateSpaceAclPayload(payload.AclWithId) if err != nil { return } - err = validateCreateSpaceSettingsPayload(payload.SpaceSettingsWithId) + aclHeadId, settingsSpaceId, err := validateCreateSpaceSettingsPayload(payload.SpaceSettingsWithId) if err != nil { return } + if aclSpaceId != payload.SpaceHeaderWithId.Id || aclSpaceId != settingsSpaceId { + err = ErrIncorrectSpaceHeader + return + } + if aclHeadId != payload.AclWithId.Id { + err = ErrIncorrectSpaceHeader + return + } - return nil + return } func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHeaderWithId) (err error) { @@ -96,7 +103,6 @@ func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHe if err != nil { return } - split := strings.Split(rawHeaderWithId.Id, ".") if len(split) != 2 { return ErrIncorrectSpaceHeader @@ -106,13 +112,18 @@ func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHe return } payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(header.Identity) + if err != nil { + return + } res, err := payloadIdentity.Verify(rawSpaceHeader.SpaceHeader, rawSpaceHeader.Signature) if err != nil || !res { err = ErrIncorrectSpaceHeader return } - id, err := cidutil.NewCidFromBytes(rawSpaceHeader.SpaceHeader) + if err != nil { + return + } requiredSpaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(header.ReplicationKey, 36)) if requiredSpaceId != rawHeaderWithId.Id { err = ErrIncorrectSpaceHeader @@ -122,7 +133,7 @@ func validateCreateSpaceHeaderPayload(rawHeaderWithId *spacesyncproto.RawSpaceHe return } -func validateCreateSpaceAclPayload(rawWithId *aclrecordproto.RawAclRecordWithId) (err error) { +func validateCreateSpaceAclPayload(rawWithId *aclrecordproto.RawAclRecordWithId) (spaceId string, err error) { if !cidutil.VerifyCid(rawWithId.Payload, rawWithId.Id) { err = objecttree.ErrIncorrectCid return @@ -134,24 +145,33 @@ func validateCreateSpaceAclPayload(rawWithId *aclrecordproto.RawAclRecordWithId) } var aclRoot aclrecordproto.AclRoot err = proto.Unmarshal(rawAcl.Payload, &aclRoot) + if err != nil { + return + } payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.Identity) + if err != nil { + return + } res, err := payloadIdentity.Verify(rawAcl.Payload, rawAcl.Signature) if err != nil || !res { err = ErrIncorrectSpaceHeader return } - masterKey, err := crypto.UnmarshalEd25519PrivateKey(aclRoot.MasterKey) - identity, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.Identity) - rawIdentity, err := identity.Raw() - signedIdentity, err := masterKey.Sign(rawIdentity) - if !bytes.Equal(signedIdentity, aclRoot.IdentitySignature) { + masterKey, err := crypto.UnmarshalEd25519PublicKeyProto(aclRoot.MasterKey) + if err != nil { + return + } + res, err = masterKey.Verify(aclRoot.Identity, aclRoot.IdentitySignature) + if err != nil || !res { err = ErrIncorrectSpaceHeader return } + spaceId = aclRoot.SpaceId + return } -func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChangeWithId) (err error) { +func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChangeWithId) (aclHeadId string, spaceId string, err error) { var raw treechangeproto.RawTreeChange err = proto.Unmarshal(rawWithId.RawChange, &raw) if err != nil { @@ -159,7 +179,13 @@ func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChange } var rootChange treechangeproto.RootChange err = proto.Unmarshal(raw.Payload, &rootChange) + if err != nil { + return + } payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(rootChange.Identity) + if err != nil { + return + } res, err := payloadIdentity.Verify(raw.Payload, raw.Signature) if err != nil || !res { err = ErrIncorrectSpaceHeader @@ -170,6 +196,8 @@ func validateCreateSpaceSettingsPayload(rawWithId *treechangeproto.RawTreeChange err = ErrIncorrectSpaceHeader return } + spaceId = rootChange.SpaceId + aclHeadId = rootChange.AclHeadId return } diff --git a/commonspace/spacestorage/spacestorage_test.go b/commonspace/spacestorage/spacestorage_test.go index 2eabb66f..d47935b0 100644 --- a/commonspace/spacestorage/spacestorage_test.go +++ b/commonspace/spacestorage/spacestorage_test.go @@ -21,40 +21,8 @@ import ( func TestSuccessHeaderPayloadForSpaceCreate(t *testing.T) { accountKeys, err := accountdata.NewRandom() require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() + _, rawHeaderWithId, err := rawHeaderWithId(accountKeys) require.NoError(t, err) - spaceHeaderSeed := make([]byte, 32) - _, err = rand.Read(spaceHeaderSeed) - require.NoError(t, err) - spaceHeaderPayload := make([]byte, 32) - _, err = rand.Read(spaceHeaderPayload) - require.NoError(t, err) - replicationKey := rand2.Uint64() - header := &spacesyncproto.SpaceHeader{ - Identity: identity, - Timestamp: time.Now().Unix(), - SpaceType: "SpaceType", - ReplicationKey: replicationKey, - Seed: spaceHeaderSeed, - SpaceHeaderPayload: spaceHeaderPayload, - } - marhalled, err := header.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marhalled) - require.NoError(t, err) - rawHeader := &spacesyncproto.RawSpaceHeader{ - SpaceHeader: marhalled, - Signature: signature, - } - marhalledRawHeader, err := rawHeader.Marshal() - require.NoError(t, err) - id, err := cidutil.NewCidFromBytes(marhalled) - require.NoError(t, err) - spaceId := fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) - rawHeaderWithId := &spacesyncproto.RawSpaceHeaderWithId{ - RawHeader: marhalledRawHeader, - Id: spaceId, - } err = validateCreateSpaceHeaderPayload(rawHeaderWithId) require.NoError(t, err) } @@ -183,46 +151,11 @@ func TestFailedHeaderPayloadForSpaceCreate_SignedWithAnotherIdentity(t *testing. func TestSuccessAclPayloadSpace(t *testing.T) { accountKeys, err := accountdata.NewRandom() + spaceId := "AnySpaceId" + _, rawWithId, err := rawAclWithId(accountKeys, spaceId) require.NoError(t, err) - identity, err := accountKeys.SignKey.GetPublic().Marshall() - require.NoError(t, err) - readKeyBytes := make([]byte, 32) - _, err = rand.Read(readKeyBytes) - require.NoError(t, err) - readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) - require.NoError(t, err) - masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() - require.NoError(t, err) - rawIdentity, err := accountKeys.SignKey.GetPublic().Raw() - require.NoError(t, err) - identitySignature, err := masterKey.Sign(rawIdentity) - require.NoError(t, err) - rawMasterKey, err := masterKey.Raw() - require.NoError(t, err) - aclRoot := aclrecordproto.AclRoot{ - Identity: identity, - MasterKey: rawMasterKey, - SpaceId: "SpaceId", - EncryptedReadKey: readKey, - Timestamp: time.Now().Unix(), - IdentitySignature: identitySignature, - } - marshalled, err := aclRoot.Marshal() - require.NoError(t, err) - signature, err := accountKeys.SignKey.Sign(marshalled) - rawAclRecord := &aclrecordproto.RawAclRecord{ - Payload: marshalled, - Signature: signature, - } - marshalledRaw, err := rawAclRecord.Marshal() - require.NoError(t, err) - aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw) - require.NoError(t, err) - rawWithId := &aclrecordproto.RawAclRecordWithId{ - Payload: marshalledRaw, - Id: aclHeadId, - } - err = validateCreateSpaceAclPayload(rawWithId) + validationSpaceId, err := validateCreateSpaceAclPayload(rawWithId) + require.Equal(t, validationSpaceId, spaceId) require.NoError(t, err) } @@ -242,7 +175,7 @@ func TestFailAclPayloadSpace_IncorrectCid(t *testing.T) { require.NoError(t, err) identitySignature, err := masterKey.Sign(rawIdentity) require.NoError(t, err) - rawMasterKey, err := masterKey.Raw() + rawMasterKey, err := masterKey.GetPublic().Marshall() require.NoError(t, err) aclRoot := aclrecordproto.AclRoot{ Identity: identity, @@ -266,7 +199,7 @@ func TestFailAclPayloadSpace_IncorrectCid(t *testing.T) { Payload: marshalledRaw, Id: aclHeadId, } - err = validateCreateSpaceAclPayload(rawWithId) + _, err = validateCreateSpaceAclPayload(rawWithId) assert.EqualErrorf(t, err, objecttree.ErrIncorrectCid.Error(), "Error should be: %v, got: %v", objecttree.ErrIncorrectCid, err) } @@ -286,7 +219,7 @@ func TestFailedAclPayloadSpace_IncorrectSignature(t *testing.T) { require.NoError(t, err) identitySignature, err := masterKey.Sign(rawIdentity) require.NoError(t, err) - rawMasterKey, err := masterKey.Raw() + rawMasterKey, err := masterKey.GetPublic().Raw() require.NoError(t, err) aclRoot := aclrecordproto.AclRoot{ Identity: identity, @@ -310,7 +243,7 @@ func TestFailedAclPayloadSpace_IncorrectSignature(t *testing.T) { Payload: marshalledRaw, Id: aclHeadId, } - err = validateCreateSpaceAclPayload(rawWithId) + _, err = validateCreateSpaceAclPayload(rawWithId) assert.NotNil(t, err) assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) } @@ -327,7 +260,7 @@ func TestFailedAclPayloadSpace_IncorrectIdentitySignature(t *testing.T) { require.NoError(t, err) masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() require.NoError(t, err) - rawMasterKey, err := masterKey.Raw() + rawMasterKey, err := masterKey.GetPublic().Marshall() require.NoError(t, err) aclRoot := aclrecordproto.AclRoot{ Identity: identity, @@ -352,7 +285,7 @@ func TestFailedAclPayloadSpace_IncorrectIdentitySignature(t *testing.T) { Payload: marshalledRaw, Id: aclHeadId, } - err = validateCreateSpaceAclPayload(rawWithId) + _, err = validateCreateSpaceAclPayload(rawWithId) assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) } @@ -367,9 +300,10 @@ func TestSuccessSettingsPayloadSpace(t *testing.T) { changePayload := make([]byte, 32) _, err = rand.Read(changePayload) require.NoError(t, err) + spaceId := "SpaceId" rootChange := &treechangeproto.RootChange{ AclHeadId: "AclHeadId", - SpaceId: "SpaceId", + SpaceId: spaceId, ChangeType: "ChangeType", Timestamp: time.Now().Unix(), Seed: spaceSettingsSeed, @@ -391,7 +325,8 @@ func TestSuccessSettingsPayloadSpace(t *testing.T) { RawChange: marshalledRawChange, Id: id, } - err = validateCreateSpaceSettingsPayload(rawIdChange) + _, validationSpaceId, err := validateCreateSpaceSettingsPayload(rawIdChange) + require.Equal(t, validationSpaceId, spaceId) require.NoError(t, err) } @@ -428,7 +363,7 @@ func TestFailSettingsPayloadSpace_InvalidSignature(t *testing.T) { RawChange: marshalledRawChange, Id: id, } - err = validateCreateSpaceSettingsPayload(rawIdChange) + _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) } @@ -467,6 +402,236 @@ func TestFailSettingsPayloadSpace_InvalidCid(t *testing.T) { RawChange: marshalledRawChange, Id: id, } - err = validateCreateSpaceSettingsPayload(rawIdChange) + _, _, err = validateCreateSpaceSettingsPayload(rawIdChange) assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) } + +func TestSuccessSameIds(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) + spacePayload := SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = ValidateSpaceStorageCreatePayload(spacePayload) + require.NoError(t, err) +} + +func TestFailWithAclWrongSpaceId(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, "spaceId") + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, aclHeadId) + spacePayload := SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = ValidateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) +} + +func TestFailWithSettingsWrongSpaceId(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + aclHeadId, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, "spaceId", aclHeadId) + spacePayload := SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = ValidateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) +} + +func TestFailWithWrongAclHeadIdInSettingsPayload(t *testing.T) { + accountKeys, err := accountdata.NewRandom() + require.NoError(t, err) + spaceId, rawHeaderWithId, err := rawHeaderWithId(accountKeys) + require.NoError(t, err) + _, rawAclWithId, err := rawAclWithId(accountKeys, spaceId) + require.NoError(t, err) + rawSettingsPayload, err := rawSettingsPayload(accountKeys, spaceId, "aclHeadId") + spacePayload := SpaceStorageCreatePayload{ + AclWithId: rawAclWithId, + SpaceHeaderWithId: rawHeaderWithId, + SpaceSettingsWithId: rawSettingsPayload, + } + err = ValidateSpaceStorageCreatePayload(spacePayload) + assert.EqualErrorf(t, err, ErrIncorrectSpaceHeader.Error(), "Error should be: %v, got: %v", ErrIncorrectSpaceHeader, err) +} + +func rawSettingsPayload(accountKeys *accountdata.AccountKeys, spaceId, aclHeadId string) (rawIdChange *treechangeproto.RawTreeChangeWithId, err error) { + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + spaceSettingsSeed := make([]byte, 32) + _, err = rand.Read(spaceSettingsSeed) + if err != nil { + return + } + changePayload := make([]byte, 32) + _, err = rand.Read(changePayload) + if err != nil { + return + } + rootChange := &treechangeproto.RootChange{ + AclHeadId: aclHeadId, + SpaceId: spaceId, + ChangeType: "ChangeType", + Timestamp: time.Now().Unix(), + Seed: spaceSettingsSeed, + Identity: identity, + ChangePayload: changePayload, + } + marshalledChange, err := rootChange.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marshalledChange) + if err != nil { + return + } + raw := &treechangeproto.RawTreeChange{ + Payload: marshalledChange, + Signature: signature, + } + marshalledRawChange, err := raw.Marshal() + id, err := cidutil.NewCidFromBytes(marshalledRawChange) + if err != nil { + return + } + rawIdChange = &treechangeproto.RawTreeChangeWithId{ + RawChange: marshalledRawChange, + Id: id, + } + + return +} + +func rawAclWithId(accountKeys *accountdata.AccountKeys, spaceId string) (aclHeadId string, rawWithId *aclrecordproto.RawAclRecordWithId, err error) { + readKeyBytes := make([]byte, 32) + _, err = rand.Read(readKeyBytes) + if err != nil { + return + } + readKey, err := accountKeys.SignKey.GetPublic().Encrypt(readKeyBytes) + if err != nil { + return + } + masterKey, _, err := crypto.GenerateRandomEd25519KeyPair() + if err != nil { + return + } + masterPubKey := masterKey.GetPublic() + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + identitySignature, err := masterKey.Sign(identity) + if err != nil { + return + } + rawMasterKey, err := masterPubKey.Marshall() + if err != nil { + return + } + aclRoot := aclrecordproto.AclRoot{ + Identity: identity, + MasterKey: rawMasterKey, + SpaceId: spaceId, + EncryptedReadKey: readKey, + Timestamp: time.Now().Unix(), + IdentitySignature: identitySignature, + } + marshalled, err := aclRoot.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marshalled) + rawAclRecord := &aclrecordproto.RawAclRecord{ + Payload: marshalled, + Signature: signature, + } + marshalledRaw, err := rawAclRecord.Marshal() + if err != nil { + return + } + aclHeadId, err = cidutil.NewCidFromBytes(marshalledRaw) + if err != nil { + return + } + rawWithId = &aclrecordproto.RawAclRecordWithId{ + Payload: marshalledRaw, + Id: aclHeadId, + } + + return +} + +func rawHeaderWithId(accountKeys *accountdata.AccountKeys) (spaceId string, rawWithId *spacesyncproto.RawSpaceHeaderWithId, err error) { + identity, err := accountKeys.SignKey.GetPublic().Marshall() + if err != nil { + return + } + spaceHeaderSeed := make([]byte, 32) + _, err = rand.Read(spaceHeaderSeed) + if err != nil { + return + } + spaceHeaderPayload := make([]byte, 32) + _, err = rand.Read(spaceHeaderPayload) + if err != nil { + return + } + replicationKey := rand2.Uint64() + header := &spacesyncproto.SpaceHeader{ + Identity: identity, + Timestamp: time.Now().Unix(), + SpaceType: "SpaceType", + ReplicationKey: replicationKey, + Seed: spaceHeaderSeed, + SpaceHeaderPayload: spaceHeaderPayload, + } + marhalled, err := header.Marshal() + if err != nil { + return + } + signature, err := accountKeys.SignKey.Sign(marhalled) + if err != nil { + return + } + rawHeader := &spacesyncproto.RawSpaceHeader{ + SpaceHeader: marhalled, + Signature: signature, + } + marhalledRawHeader, err := rawHeader.Marshal() + if err != nil { + return + } + id, err := cidutil.NewCidFromBytes(marhalled) + if err != nil { + return + } + spaceId = fmt.Sprintf("%s.%s", id, strconv.FormatUint(replicationKey, 36)) + rawWithId = &spacesyncproto.RawSpaceHeaderWithId{ + RawHeader: marhalledRawHeader, + Id: spaceId, + } + + return +}