Skip to content

Commit 7e39c90

Browse files
authored
Parse RSA header tag for signature info (#58)
* add rockylinux example + parse rsa header * decode pgp payloads the same for all types * do not attempt to decode unknown signature types
1 parent e8ca378 commit 7e39c90

7 files changed

Lines changed: 469 additions & 117 deletions

File tree

go.mod

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
module github.com/knqyf263/go-rpmdb
22

3-
go 1.18
3+
go 1.22.0
4+
5+
toolchain go1.24.1
46

57
require (
68
github.com/glebarez/go-sqlite v1.20.3
79
github.com/hashicorp/go-multierror v1.1.1
8-
github.com/stretchr/testify v1.7.0
10+
github.com/stretchr/testify v1.10.0
911
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
1012
)
1113

1214
require (
13-
github.com/davecgh/go-spew v1.1.0 // indirect
15+
github.com/davecgh/go-spew v1.1.1 // indirect
1416
github.com/dustin/go-humanize v1.0.1 // indirect
1517
github.com/google/uuid v1.3.0 // indirect
1618
github.com/hashicorp/errwrap v1.0.0 // indirect
19+
github.com/kr/pretty v0.2.1 // indirect
1720
github.com/mattn/go-isatty v0.0.17 // indirect
1821
github.com/pmezard/go-difflib v1.0.0 // indirect
1922
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect
20-
golang.org/x/sys v0.4.0 // indirect
21-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
23+
golang.org/x/sys v0.30.0 // indirect
24+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
25+
gopkg.in/yaml.v3 v3.0.1 // indirect
2226
modernc.org/libc v1.22.2 // indirect
2327
modernc.org/mathutil v1.5.0 // indirect
2428
modernc.org/memory v1.5.0 // indirect

go.sum

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,41 @@
1-
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
33
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
44
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
55
github.com/glebarez/go-sqlite v1.20.3 h1:89BkqGOXR9oRmG58ZrzgoY/Fhy5x0M+/WV48U5zVrZ4=
66
github.com/glebarez/go-sqlite v1.20.3/go.mod h1:u3N6D/wftiAzIOJtZl6BmedqxmmkDfH3q+ihjqxC9u0=
77
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
8+
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
89
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
910
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
1011
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
1112
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
1213
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
1314
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
15+
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
16+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
17+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
18+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
19+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
1420
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
1521
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
1622
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1723
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1824
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
1925
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M=
2026
github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
21-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
22-
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
23-
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
27+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
28+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
2429
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
25-
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
26-
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
30+
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
31+
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
2732
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
2833
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
29-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
3034
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
31-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
32-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
35+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
36+
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
37+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
38+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
3339
modernc.org/libc v1.22.2 h1:4U7v51GyhlWqQmwCHj28Rdq2Yzwk55ovjFrdPjs8Hb0=
3440
modernc.org/libc v1.22.2/go.mod h1:uvQavJ1pZ0hIoC/jfqNoMLURIMhKzINIWypNM17puug=
3541
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=

pkg/package.go

Lines changed: 122 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/binary"
66
"encoding/hex"
77
"fmt"
8+
"io"
89
"path"
910
"strings"
1011
"time"
@@ -26,6 +27,7 @@ type PackageInfo struct {
2627
Summary string
2728
PGP string
2829
SigMD5 string
30+
RSAHeader string
2931
DigestAlgorithm DigestAlgorithm
3032
InstallTime int
3133
BaseNames []string
@@ -236,118 +238,137 @@ func getNEVRA(indexEntries []indexEntry) (*PackageInfo, error) {
236238
// It is just string that we need to encode to hex
237239
digest := ie.Data
238240
pkgInfo.SigMD5 = hex.EncodeToString(digest)
241+
case RPMTAG_RSAHEADER:
242+
if ie.Info.Type != RPM_BIN_TYPE {
243+
return nil, xerrors.New("invalid rsa signature")
244+
}
245+
val, err := parsePGP(ie)
246+
if err != nil {
247+
return nil, xerrors.Errorf("failed to parse rsa signature: %w", err)
248+
}
249+
pkgInfo.RSAHeader = val
239250
case RPMTAG_PGP:
240-
type pgpSig struct {
241-
_ [3]byte
242-
Date int32
243-
KeyID [8]byte
244-
PubKeyAlgo uint8
245-
HashAlgo uint8
251+
if ie.Info.Type != RPM_BIN_TYPE {
252+
return nil, xerrors.New("invalid pgp signature")
246253
}
247-
248-
type textSig struct {
249-
_ [2]byte
250-
PubKeyAlgo uint8
251-
HashAlgo uint8
252-
_ [4]byte
253-
Date int32
254-
_ [4]byte
255-
KeyID [8]byte
254+
val, err := parsePGP(ie)
255+
if err != nil {
256+
return nil, xerrors.Errorf("failed to parse pgp signature: %w", err)
256257
}
258+
pkgInfo.PGP = val
259+
}
260+
}
257261

258-
type pgp4Sig struct {
259-
_ [2]byte
260-
PubKeyAlgo uint8
261-
HashAlgo uint8
262-
_ [17]byte
263-
KeyID [8]byte
264-
_ [2]byte
265-
Date int32
266-
}
262+
return pkgInfo, nil
263+
}
267264

268-
pubKeyLookup := map[uint8]string{
269-
0x01: "RSA",
270-
}
271-
hashLookup := map[uint8]string{
272-
0x02: "SHA1",
273-
0x08: "SHA256",
274-
}
265+
type pgpSig struct {
266+
_ [3]byte
267+
Date int32
268+
KeyID [8]byte
269+
PubKeyAlgo uint8
270+
HashAlgo uint8
271+
}
275272

276-
if ie.Info.Type != RPM_BIN_TYPE {
277-
return nil, xerrors.New("invalid PGP signature")
278-
}
273+
type textSig struct {
274+
_ [2]byte
275+
PubKeyAlgo uint8
276+
HashAlgo uint8
277+
_ [4]byte
278+
Date int32
279+
_ [4]byte
280+
KeyID [8]byte
281+
}
279282

280-
var tag, signatureType, version uint8
281-
r := bytes.NewReader(ie.Data)
282-
err := binary.Read(r, binary.BigEndian, &tag)
283-
if err != nil {
284-
return nil, err
285-
}
286-
err = binary.Read(r, binary.BigEndian, &signatureType)
287-
if err != nil {
288-
return nil, err
289-
}
290-
err = binary.Read(r, binary.BigEndian, &version)
283+
type pgp4Sig struct {
284+
_ [2]byte
285+
PubKeyAlgo uint8
286+
HashAlgo uint8
287+
_ [17]byte
288+
KeyID [8]byte
289+
_ [2]byte
290+
Date int32
291+
}
292+
293+
var pubKeyLookup = map[uint8]string{
294+
0x01: "RSA",
295+
}
296+
var hashLookup = map[uint8]string{
297+
0x02: "SHA1",
298+
0x08: "SHA256",
299+
}
300+
301+
func parsePGP(ie indexEntry) (string, error) {
302+
var tag, signatureType, version uint8
303+
304+
r := bytes.NewReader(ie.Data)
305+
err := binary.Read(r, binary.BigEndian, &tag)
306+
if err != nil {
307+
return "", err
308+
}
309+
err = binary.Read(r, binary.BigEndian, &signatureType)
310+
if err != nil {
311+
return "", err
312+
}
313+
err = binary.Read(r, binary.BigEndian, &version)
314+
if err != nil {
315+
return "", err
316+
}
317+
318+
switch signatureType {
319+
case 0x01:
320+
switch version {
321+
case 0x1c:
322+
sig := textSig{}
323+
err = binary.Read(r, binary.BigEndian, &sig)
291324
if err != nil {
292-
return nil, err
293-
}
294-
295-
var pubKeyAlgo, hashAlgo, pkgDate string
296-
var keyId [8]byte
297-
298-
switch signatureType {
299-
case 0x01:
300-
switch version {
301-
case 0x1c:
302-
sig := textSig{}
303-
err = binary.Read(r, binary.BigEndian, &sig)
304-
if err != nil {
305-
return nil, xerrors.Errorf("invalid PGP signature on decode: %w", err)
306-
}
307-
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
308-
hashAlgo = hashLookup[sig.HashAlgo]
309-
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
310-
keyId = sig.KeyID
311-
default:
312-
sig := pgpSig{}
313-
err = binary.Read(r, binary.BigEndian, &sig)
314-
if err != nil {
315-
return nil, xerrors.Errorf("invalid PGP signature on decode: %w", err)
316-
}
317-
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
318-
hashAlgo = hashLookup[sig.HashAlgo]
319-
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
320-
keyId = sig.KeyID
321-
}
322-
case 0x02:
323-
switch version {
324-
case 0x33:
325-
sig := pgp4Sig{}
326-
err = binary.Read(r, binary.BigEndian, &sig)
327-
if err != nil {
328-
return nil, xerrors.Errorf("invalid PGP signature on decode: %w", err)
329-
}
330-
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
331-
hashAlgo = hashLookup[sig.HashAlgo]
332-
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
333-
keyId = sig.KeyID
334-
default:
335-
sig := pgpSig{}
336-
err = binary.Read(r, binary.BigEndian, &sig)
337-
if err != nil {
338-
return nil, xerrors.Errorf("invalid PGP signature on decode: %w", err)
339-
}
340-
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
341-
hashAlgo = hashLookup[sig.HashAlgo]
342-
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
343-
keyId = sig.KeyID
344-
}
325+
return "", fmt.Errorf("invalid PGP signature on decode: %w", err)
345326
}
346-
pkgInfo.PGP = fmt.Sprintf("%s/%s, %s, Key ID %x", pubKeyAlgo, hashAlgo, pkgDate, keyId)
327+
328+
pubKeyAlgo := pubKeyLookup[sig.PubKeyAlgo]
329+
hashAlgo := hashLookup[sig.HashAlgo]
330+
pkgDate := time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
331+
keyId := sig.KeyID
332+
333+
return fmt.Sprintf("%s/%s, %s, Key ID %x", pubKeyAlgo, hashAlgo, pkgDate, keyId), nil
334+
default:
335+
return decodePGPSig(version, r)
347336
}
337+
case 0x02:
338+
return decodePGPSig(version, r)
348339
}
349340

350-
return pkgInfo, nil
341+
return "", nil
342+
}
343+
344+
func decodePGPSig(version uint8, r io.Reader) (string, error) {
345+
var pubKeyAlgo, hashAlgo, pkgDate string
346+
var keyId [8]byte
347+
348+
switch {
349+
case version > 0x15:
350+
sig := pgp4Sig{}
351+
err := binary.Read(r, binary.BigEndian, &sig)
352+
if err != nil {
353+
return "", fmt.Errorf("invalid PGP v4 signature on decode: %w", err)
354+
}
355+
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
356+
hashAlgo = hashLookup[sig.HashAlgo]
357+
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
358+
keyId = sig.KeyID
359+
360+
default:
361+
sig := pgpSig{}
362+
err := binary.Read(r, binary.BigEndian, &sig)
363+
if err != nil {
364+
return "", fmt.Errorf("invalid PGP signature on decode: %w", err)
365+
}
366+
pubKeyAlgo = pubKeyLookup[sig.PubKeyAlgo]
367+
hashAlgo = hashLookup[sig.HashAlgo]
368+
pkgDate = time.Unix(int64(sig.Date), 0).UTC().Format("Mon Jan _2 15:04:05 2006")
369+
keyId = sig.KeyID
370+
}
371+
return fmt.Sprintf("%s/%s, %s, Key ID %x", pubKeyAlgo, hashAlgo, pkgDate, keyId), nil
351372
}
352373

353374
const (
@@ -389,7 +410,7 @@ func parseStringArray(data []byte) []string {
389410
}
390411

391412
func (p *PackageInfo) InstalledFileNames() ([]string, error) {
392-
if len(p.DirNames) == 0 || len(p.DirIndexes) == 0 || len(p.BaseNames) == 0 {
413+
if p == nil || len(p.DirNames) == 0 || len(p.DirIndexes) == 0 || len(p.BaseNames) == 0 {
393414
return nil, nil
394415
}
395416

0 commit comments

Comments
 (0)