@@ -19,11 +19,8 @@ package rpmutils
1919import (
2020 "bytes"
2121 "crypto"
22- "crypto/md5"
23- "errors"
2422 "hash"
2523 "io"
26- "io/ioutil"
2724 "os"
2825 "path"
2926 "time"
@@ -54,21 +51,16 @@ func (opts *SignatureOptions) creationTime() time.Time {
5451 return time .Now ()
5552}
5653
57- func makeSignature (stream io. Reader , key * packet.PrivateKey , opts * SignatureOptions ) ([]byte , error ) {
58- hash := opts .hash ()
54+ func makeSignature (h hash. Hash , key * packet.PrivateKey , opts * SignatureOptions ) ([]byte , error ) {
55+ hashType := opts .hash ()
5956 sig := & packet.Signature {
6057 SigType : packet .SigTypeBinary ,
6158 CreationTime : opts .creationTime (),
6259 PubKeyAlgo : key .PublicKey .PubKeyAlgo ,
63- Hash : hash ,
60+ Hash : hashType ,
6461 IssuerKeyId : & key .KeyId ,
6562 }
66- h := hash .New ()
67- _ , err := io .Copy (h , stream )
68- if err != nil {
69- return nil , err
70- }
71- err = sig .Sign (h , key , nil )
63+ err := sig .Sign (h , key , nil )
7264 if err != nil {
7365 return nil , err
7466 }
@@ -103,43 +95,59 @@ func getSha1(sigHeader *rpmHeader) string {
10395 return vals [0 ]
10496}
10597
106- func checkMd5 (sigHeader * rpmHeader , h hash. Hash ) bool {
107- sigmd5 , err := sigHeader .GetBytes ( SIG_MD5 - _SIGHEADER_TAG_BASE )
98+ func getSha256 (sigHeader * rpmHeader ) string {
99+ vals , err := sigHeader .GetStrings ( SIG_SHA256 )
108100 if err != nil {
109- return true
101+ return ""
110102 }
111- return bytes .Equal (sigmd5 , h .Sum (nil ))
103+ return vals [0 ]
104+ }
105+
106+ func getHashAndType (sigHeader * rpmHeader ) (string , crypto.Hash ) {
107+ // RPM v4 introduced SHA256 header signatures, prefer them over the
108+ // previous SHA1
109+ if h := getSha256 (sigHeader ); h != "" {
110+ return h , crypto .SHA256
111+ }
112+ return getSha1 (sigHeader ), crypto .SHA1
113+ }
114+
115+ func digestForSigning (sigHeader , genHeader * rpmHeader , payloadReader io.Reader , opts * SignatureOptions ) (genHash , combinedHash hash.Hash , err error ) {
116+ genHash , combinedHash = opts .hash ().New (), opts .hash ().New ()
117+ // write header
118+ genHash .Write (genHeader .orig )
119+ combinedHash .Write (genHeader .orig )
120+ // write and verify payload
121+ err = digestPayload (sigHeader , genHeader , payloadReader , []io.Writer {combinedHash })
122+ return genHash , combinedHash , err
112123}
113124
114125// SignRpmStream reads an RPM and signs it, returning the set of headers updated with the new signature.
115126func SignRpmStream (stream io.Reader , key * packet.PrivateKey , opts * SignatureOptions ) (header * RpmHeader , err error ) {
116127 lead , sigHeader , err := readSignatureHeader (stream )
117128 if err != nil {
118- return
129+ return nil , err
119130 }
120- // parse the general header and also tee it into a buffer
121- genHeaderBuf := new (bytes.Buffer )
122- headerTee := io .TeeReader (stream , genHeaderBuf )
123- genHeader , err := readHeader (headerTee , getSha1 (sigHeader ), sigHeader .isSource , false )
131+ // parse the general header
132+ headerDigestValue , headerDigestType := getHashAndType (sigHeader )
133+ genHeader , err := readHeader (stream , headerDigestValue , headerDigestType , sigHeader .isSource , false )
124134 if err != nil {
125- return
135+ return nil , err
126136 }
127- genHeaderBlob := genHeaderBuf .Bytes ()
128- // chain the buffered general header to the rest of the payload, and digest the whole lot of it
129- genHeaderAndPayload := io .MultiReader (bytes .NewReader (genHeaderBlob ), stream )
130- payloadDigest := md5 .New ()
131- payloadTee := io .TeeReader (genHeaderAndPayload , payloadDigest )
132- sigPgp , err := makeSignature (payloadTee , key , opts )
137+ // hash and sign header
138+ genHash , combinedHash , err := digestForSigning (sigHeader , genHeader , stream , opts )
133139 if err != nil {
134- return
135- }
136- if ! checkMd5 (sigHeader , payloadDigest ) {
137- return nil , errors .New ("md5 digest mismatch" )
140+ return nil , err
138141 }
139- sigRsa , err := makeSignature (bytes .NewReader (genHeaderBlob ), key , opts )
142+ // sign header and payload
143+ sigPgp , err := makeSignature (combinedHash , key , opts )
140144 if err != nil {
141145 return
142146 }
147+ sigRsa , err := makeSignature (genHash , key , opts )
148+ if err != nil {
149+ return nil , err
150+ }
143151 insertSignatures (sigHeader , sigPgp , sigRsa )
144152 return & RpmHeader {
145153 lead : lead ,
@@ -149,6 +157,34 @@ func SignRpmStream(stream io.Reader, key *packet.PrivateKey, opts *SignatureOpti
149157 }, nil
150158}
151159
160+ func getPayloadDigest (header * rpmHeader ) (string , crypto.Hash ) {
161+ digests , err := header .GetStrings (PAYLOADDIGEST )
162+ if err != nil || len (digests ) == 0 {
163+ // no payload digest
164+ return "" , 0
165+ }
166+ digest := digests [0 ]
167+ algos , err := header .GetUint32s (PAYLOADDIGESTALGO )
168+ if err != nil || len (algos ) == 0 {
169+ return "" , 0
170+ }
171+ switch algos [0 ] {
172+ case HASH_MD5 :
173+ return digest , crypto .MD5
174+ case HASH_SHA1 :
175+ return digest , crypto .SHA1
176+ case HASH_SHA256 :
177+ return digest , crypto .SHA256
178+ case HASH_SHA384 :
179+ return digest , crypto .SHA384
180+ case HASH_SHA512 :
181+ return digest , crypto .SHA512
182+ case HASH_SHA224 :
183+ return digest , crypto .SHA224
184+ }
185+ return "" , 0
186+ }
187+
152188func canOverwrite (ininfo , outinfo os.FileInfo ) bool {
153189 if ! outinfo .Mode ().IsRegular () {
154190 return false
@@ -216,7 +252,7 @@ func rewriteRpm(infile *os.File, outpath string, header *RpmHeader) error {
216252 }
217253 if outstream == nil {
218254 // write-rename
219- tempfile , err := ioutil . TempFile (path .Dir (outpath ), path .Base (outpath ))
255+ tempfile , err := os . CreateTemp (path .Dir (outpath ), path .Base (outpath ))
220256 if err != nil {
221257 return err
222258 }
@@ -275,7 +311,7 @@ func writeRpm(infile io.ReadSeeker, outstream io.Writer, sigHeader *rpmHeader) e
275311 if err = sigHeader .WriteTo (outstream , RPMTAG_HEADERSIGNATURES ); err != nil {
276312 return err
277313 }
278- if _ , err := infile .Seek (int64 (len (lead )+ sigHeader .origSize ), 0 ); err != nil {
314+ if _ , err := infile .Seek (int64 (len (lead )+ len ( sigHeader .orig ) ), 0 ); err != nil {
279315 return err
280316 }
281317 _ , err = io .Copy (outstream , infile )
0 commit comments