@@ -21,9 +21,9 @@ import (
2121 "crypto"
2222 "encoding/binary"
2323 "errors"
24+ "fmt"
2425 "hash"
2526 "io"
26- "io/ioutil"
2727
2828 "github.com/sassoftware/relic/v7/lib/binpatch"
2929)
@@ -33,7 +33,7 @@ func Digest(r io.Reader, hashFunc crypto.Hash) (*CabinetDigest, error) {
3333 var d hash.Hash
3434 var dw io.Writer
3535 if hashFunc == 0 {
36- dw = ioutil .Discard
36+ dw = io .Discard
3737 } else {
3838 d = hashFunc .New ()
3939 dw = d
@@ -45,47 +45,68 @@ func Digest(r io.Reader, hashFunc crypto.Hash) (*CabinetDigest, error) {
4545 if cab .Header .Magic != Magic {
4646 return nil , errors .New ("not a cab file" )
4747 }
48-
4948 outHeader := cab .Header
49+ var addOffset int
5050 if cab .Header .Flags & FlagReservePresent != 0 {
51+ // read reserve header
5152 if err := binary .Read (r , binary .LittleEndian , & cab .ReserveHeader ); err != nil {
5253 return nil , err
5354 }
54- if cab .ReserveHeader .HeaderSize > 0 {
55- if cab .ReserveHeader .HeaderSize != 20 {
56- return nil , errors .New ("unknown reserved data" )
55+ if cab .ReserveHeader .HeaderSize < signatureHeaderSize || cab .ReserveHeader .FolderSize != 0 || cab .ReserveHeader .DataSize != 0 {
56+ return nil , errors .New ("unknown reserved data" )
57+ }
58+ cab .SignatureHeader = new (SignatureHeader )
59+ if err := binary .Read (r , binary .LittleEndian , cab .SignatureHeader ); err != nil {
60+ return nil , err
61+ }
62+ if padding := cab .ReserveHeader .HeaderSize - signatureHeaderSize ; padding > 0 {
63+ // cabinet files may be created with space reserved; ensure in this case that it's all zeroed out
64+ if cab .SignatureHeader .CabinetSize != 0 {
65+ // must not have both padding and an actual signature header
66+ return nil , fmt .Errorf ("reserve header for signature is %d bytes; expected %d bytes" ,
67+ cab .ReserveHeader .HeaderSize , signatureHeaderSize )
5768 }
58- cab . SignatureHeader = new ( SignatureHeader )
59- if err := binary . Read (r , binary . LittleEndian , cab . SignatureHeader ); err != nil {
69+ pbuf := make ([] byte , padding )
70+ if _ , err := io . ReadFull (r , pbuf ); err != nil {
6071 return nil , err
6172 }
62- if cab .Header .TotalSize != cab .SignatureHeader .CabinetSize {
63- return nil , errors .New ("mismatch between cabinet size and signature header size" )
73+ for _ , v := range pbuf {
74+ if v != 0 {
75+ return nil , errors .New ("invalid padding in signature reserve header" )
76+ }
6477 }
65- } else {
66- return nil , errors .New ("unknown reserved data" )
67- }
68- if cab .ReserveHeader .FolderSize != 0 || cab .ReserveHeader .DataSize != 0 {
69- return nil , errors .New ("unknown reserved data" )
78+ // remove padding, since the actual signature goes at the end of the file
79+ addOffset -= int (padding )
80+ cab .SignatureHeader = nil
81+ } else if cab .Header .TotalSize != cab .SignatureHeader .CabinetSize {
82+ // signature header (if present) must agree with cabinet header
83+ return nil , fmt .Errorf ("cabinet size is %d but signature header specifies %d bytes" ,
84+ cab .Header .TotalSize , cab .SignatureHeader .CabinetSize )
7085 }
86+ } else {
87+ // make space for a new reserve header
88+ addOffset += reserveHeaderSize + signatureHeaderSize
7189 }
7290 if cab .Header .Flags & (FlagPrevCabinet | FlagNextCabinet ) != 0 {
7391 return nil , errors .New ("multipart cab files are not supported" )
7492 } else if cab .Header .Flags &^FlagReservePresent != 0 {
7593 return nil , errors .New ("unsupported flags in cabinet file" )
7694 }
77- var addOffset uint32
78- var outSigHeader SignatureHeader
79- if cab .SignatureHeader == nil {
80- // make a new header and increment all the file offsets to make room for it
81- addOffset = 24
82- outHeader .TotalSize += addOffset
83- outHeader .Flags |= FlagReservePresent
84- outHeader .OffsetFiles += addOffset
85- outSigHeader .Unknown1 = 0x100000
86- outSigHeader .CabinetSize = outHeader .TotalSize
87- } else {
88- outSigHeader = * cab .SignatureHeader
95+ // add space for signature header, or remove excess padding
96+ add32 (& outHeader .TotalSize , addOffset )
97+ add32 (& outHeader .OffsetFiles , addOffset )
98+ outHeader .Flags |= FlagReservePresent
99+ // construct signature header
100+ outReserveHeader := ReserveHeader {HeaderSize : signatureHeaderSize }
101+ outSigHeader := SignatureHeader {
102+ Unknown1 : 0x100000 ,
103+ CabinetSize : outHeader .TotalSize ,
104+ }
105+ if cab .SignatureHeader != nil {
106+ // preserve unknown fields from old signature header just in case they're important
107+ outSigHeader .Unknown1 = cab .SignatureHeader .Unknown1
108+ outSigHeader .Unknown2 = cab .SignatureHeader .Unknown2
109+ outSigHeader .Unknown3 = cab .SignatureHeader .Unknown3
89110 }
90111 // digest the header
91112 sb := sigBlob {
@@ -105,26 +126,30 @@ func Digest(r io.Reader, hashFunc crypto.Hash) (*CabinetDigest, error) {
105126 // save the updated header for writing out later
106127 patched := bytes .NewBuffer (make ([]byte , 0 , outHeader .OffsetFiles ))
107128 _ = binary .Write (patched , binary .LittleEndian , outHeader )
108- _ = binary .Write (patched , binary .LittleEndian , ReserveHeader { 20 , 0 , 0 } )
129+ _ = binary .Write (patched , binary .LittleEndian , outReserveHeader )
109130 _ = binary .Write (patched , binary .LittleEndian , outSigHeader )
110131 w := io .MultiWriter (dw , patched )
132+ // add offset to folder headers
111133 var fh FolderHeader
112134 for i := 0 ; i < int (cab .Header .NumFolders ); i ++ {
113135 if err := binary .Read (r , binary .LittleEndian , & fh ); err != nil {
114136 return nil , err
115137 }
116- fh .Offset += addOffset
138+ add32 ( & fh .Offset , addOffset )
117139 _ = binary .Write (w , binary .LittleEndian , fh )
118140 }
141+ // digest file contents
119142 if _ , err := io .CopyN (dw , r , int64 (cab .Header .TotalSize - cab .Header .OffsetFiles )); err != nil {
120143 return nil , err
121144 }
122145 if cab .SignatureHeader != nil {
146+ // read old signature for verification purposes
123147 cab .Signature = make ([]byte , cab .SignatureHeader .SignatureSize )
124148 if _ , err := io .ReadFull (r , cab .Signature ); err != nil {
125149 return nil , err
126150 }
127151 }
152+ // ensure there is nothing after the cabinet and signature
128153 if _ , err := r .Read (make ([]byte , 1 )); err == nil {
129154 return nil , errors .New ("trailing garbage after cabinet" )
130155 } else if err != io .EOF {
@@ -134,7 +159,12 @@ func Digest(r io.Reader, hashFunc crypto.Hash) (*CabinetDigest, error) {
134159 if d != nil {
135160 imprint = d .Sum (nil )
136161 }
137- return & CabinetDigest {cab , imprint , hashFunc , patched .Bytes ()}, nil
162+ return & CabinetDigest {
163+ Cabinet : cab ,
164+ Imprint : imprint ,
165+ HashFunc : hashFunc ,
166+ Patched : patched .Bytes (),
167+ }, nil
138168}
139169
140170// Parse the cabinet file header and return it
@@ -160,3 +190,7 @@ func (d *CabinetDigest) MakePatch(pkcs []byte) *binpatch.PatchSet {
160190 p .Add (int64 (d .Cabinet .Header .TotalSize ), int64 (d .Cabinet .SignatureHeader .Size ()), padded )
161191 return p
162192}
193+
194+ func add32 (offset * uint32 , increment int ) {
195+ * offset = uint32 (int64 (* offset ) + int64 (increment ))
196+ }
0 commit comments