@@ -22,7 +22,6 @@ import (
2222 cidlink "github.com/ipld/go-ipld-prime/linking/cid"
2323 grpcpeer "google.golang.org/grpc/peer"
2424
25- "github.com/sourcenetwork/corelog"
2625 "github.com/sourcenetwork/immutable"
2726
2827 "github.com/sourcenetwork/defradb/acp/dac"
@@ -31,6 +30,7 @@ import (
3130 "github.com/sourcenetwork/defradb/client"
3231 "github.com/sourcenetwork/defradb/crypto"
3332 "github.com/sourcenetwork/defradb/errors"
33+ coreblock "github.com/sourcenetwork/defradb/internal/core/block"
3434 "github.com/sourcenetwork/defradb/internal/datastore"
3535 acpDB "github.com/sourcenetwork/defradb/internal/db/acp"
3636 "github.com/sourcenetwork/defradb/internal/encryption"
@@ -290,16 +290,14 @@ func (s *pubSubService) handleFetchEncryptionKeyResponses(
290290 respChan = nextRespChan
291291 continue
292292 }
293- items , ok := s .tryHandleFetchEncryptionKeyResponse (resp , req , privateKey )
293+ items , ok , err := s .tryHandleFetchEncryptionKeyResponse (resp , req , privateKey , false /* skipVerify */ )
294294 if ! ok {
295+ if err != nil {
296+ log .ErrorContextE (s .ctx , "Failed handling of encryption key response" , err )
297+ }
295298 continue
296299 }
297300
298- // TODO: If multi-key requests become common, aggregate partial
299- // responses from multiple peers until every requested link is found or
300- // the timeout fires. A single valid response may contain fewer blocks
301- // than the request asked for.
302- // https://github.com/sourcenetwork/defradb/issues/4947
303301 result <- encryption.Result {Items : items }
304302 return
305303
@@ -364,37 +362,35 @@ func (s *pubSubService) tryHandleFetchEncryptionKeyResponse(
364362 resp client.PubsubResponse ,
365363 req * fetchEncryptionKeyRequest ,
366364 privateKey * ecdh.PrivateKey ,
367- ) ([]encryption.Item , bool ) {
365+ skipVerify bool ,
366+ ) ([]encryption.Item , bool , error ) {
368367 if resp .Err != nil {
369- log .ErrorContextE (s .ctx , "encryption key peer reply carried error" , resp .Err )
370- return nil , false
368+ return nil , false , errors .Join (ErrPeerErrorKeyReply , resp .Err )
371369 }
372370
373371 var keyResp fetchEncryptionKeyReply
374372 if err := cbor .Unmarshal (resp .Data , & keyResp ); err != nil {
375- log .ErrorContextE (s .ctx , "Failed to unmarshal encryption key response" , err )
376- return nil , false
373+ return nil , false , errors .Join (ErrEncryptionKeyUnmarshal , err )
377374 }
378375
379376 if len (keyResp .Blocks ) == 0 {
380377 // Peer didn't have the key; keep waiting for the one that does.
381- return nil , false
378+ return nil , false , nil
382379 }
383380 if len (keyResp .Links ) != len (keyResp .Blocks ) {
384- log .ErrorContext (
385- s .ctx ,
386- "encryption key peer reply had mismatched links and blocks" ,
387- corelog .Int ("LinkCount" , len (keyResp .Links )),
388- corelog .Int ("BlockCount" , len (keyResp .Blocks )),
389- )
390- return nil , false
381+ return nil , false , NewErrReplyLinksAndBlocksMismatch (len (keyResp .Links ), len (keyResp .Blocks ))
391382 }
392383
393384 senderID := keyResp .Sender
394385 if senderID == "" {
395386 senderID = resp .From
396387 }
397388
389+ reqSet := make (map [string ]struct {}, len (req .Links ))
390+ for _ , l := range req .Links {
391+ reqSet [string (l )] = struct {}{}
392+ }
393+
398394 resultEncItems := make ([]encryption.Item , 0 , len (keyResp .Blocks ))
399395 for i , block := range keyResp .Blocks {
400396 decryptedData , err := crypto .DecryptECIES (
@@ -405,25 +401,41 @@ func (s *pubSubService) tryHandleFetchEncryptionKeyResponse(
405401 crypto .WithPubKeyPrepended (false ),
406402 )
407403 if err != nil {
408- log .ErrorContextE (s .ctx , "Failed to decrypt encryption key" , err )
409- return nil , false
404+ return nil , false , errors .Join (ErrDecryptEncryptionKey , err )
405+ }
406+
407+ var encBlock coreblock.Encryption
408+ err = encBlock .Unmarshal (decryptedData )
409+ if err != nil {
410+ return nil , false , errors .Join (ErrDecodingEncryptionKey , err )
411+ }
412+
413+ if ! skipVerify {
414+ link , err := s .encStore .computeBlockLink (s .ctx , encBlock )
415+ if err != nil {
416+ return nil , false , errors .Join (ErrKeyCIDGeneration , err )
417+ }
418+
419+ if ! bytes .Equal (keyResp .Links [i ], link ) {
420+ return nil , false , ErrEncryptionKeyCIDMismatch
421+ }
422+
423+ if _ , ok := reqSet [string (link )]; ! ok {
424+ return nil , false , ErrEncryptionKeyCIDMismatch
425+ }
410426 }
411427
412- if _ , err := s .encStore .put (context .Background (), decryptedData ); err != nil {
413- log .ErrorContextE (s .ctx , "Failed to store encryption key" , err )
414- return nil , false
428+ if _ , err := s .encStore .putBlock (context .Background (), encBlock ); err != nil {
429+ return nil , false , errors .Join (ErrEncryptionKeyStore , err )
415430 }
416431
417- // todo: verify incoming response order block/CIDs match the request
418- // current implementation assumes trusted response ordering
419- // https://github.com/sourcenetwork/defradb/issues/4948
420432 resultEncItems = append (resultEncItems , encryption.Item {
421433 Link : keyResp .Links [i ],
422434 Block : decryptedData ,
423435 })
424436 }
425437
426- return resultEncItems , true
438+ return resultEncItems , true , nil
427439}
428440
429441// makeAssociatedData creates the associated data for the encryption key request
0 commit comments