Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add signature support for the RPM module #27069

Merged
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9fdaf1c
support gpg sign for rpm
ExplodingDragon Sep 14, 2023
d2cf61a
Delete routers/api/packages/rpm/rpm.go.orig
ExplodingDragon Sep 14, 2023
3aff155
Merge branch 'go-gitea:main' into feature-support-rpm-gpgsign
ExplodingDragon Oct 9, 2023
6726a26
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Oct 15, 2023
3b940d6
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Jan 12, 2024
9b7585c
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Mar 19, 2024
9215fa6
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon May 13, 2024
45fc0ce
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon May 15, 2024
4b7ac81
upgrade go-rpmutils to v0.4.0
ExplodingDragon May 15, 2024
6ee4a63
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon May 20, 2024
e695115
Merge branch 'go-gitea:main' into feature-support-rpm-gpgsign
ExplodingDragon May 21, 2024
ca21f30
add test
ExplodingDragon May 21, 2024
181cac8
add test
ExplodingDragon May 21, 2024
613045b
clean style
ExplodingDragon May 21, 2024
7c0b523
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon May 24, 2024
2c17a43
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Jun 14, 2024
a45daa0
Merge branch 'feature-support-rpm-gpgsign' of https://github.com/Expl…
ExplodingDragon Jun 14, 2024
bd72a8f
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Jun 14, 2024
a48fd6f
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Aug 1, 2024
7ebc829
fix typo
ExplodingDragon Aug 1, 2024
8278cd3
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Aug 2, 2024
954e8ff
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Aug 3, 2024
4ff9396
clean style
ExplodingDragon Aug 3, 2024
b7337d4
Merge remote-tracking branch 'origin/feature-support-rpm-gpgsign' int…
ExplodingDragon Aug 3, 2024
d2d961a
Merge branch 'main' into feature-support-rpm-gpgsign
ExplodingDragon Aug 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2555,7 +2555,8 @@ LEVEL = Info
;LIMIT_SIZE_SWIFT = -1
;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`)
;LIMIT_SIZE_VAGRANT = -1

;; Resign RPM packages (using v4 format, not compatible with CentOS 7 or older)
;RPM_SIGN_ENABLED = false
ExplodingDragon marked this conversation as resolved.
Show resolved Hide resolved
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; default storage for attachments, lfs and avatars
Expand Down
2 changes: 2 additions & 0 deletions modules/setting/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var (
LimitSizeRubyGems int64
LimitSizeSwift int64
LimitSizeVagrant int64
RPMSignEnabled bool
}{
Enabled: true,
LimitTotalOwnerCount: -1,
Expand Down Expand Up @@ -97,6 +98,7 @@ func loadPackagesFrom(rootCfg ConfigProvider) (err error) {
Packages.LimitSizeRubyGems = mustBytes(sec, "LIMIT_SIZE_RUBYGEMS")
Packages.LimitSizeSwift = mustBytes(sec, "LIMIT_SIZE_SWIFT")
Packages.LimitSizeVagrant = mustBytes(sec, "LIMIT_SIZE_VAGRANT")
Packages.RPMSignEnabled = sec.Key("RPM_SIGN_ENABLED").MustBool(false)
return nil
}

Expand Down
16 changes: 15 additions & 1 deletion routers/api/packages/rpm/rpm.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,21 @@ func UploadPackageFile(ctx *context.Context) {
}
defer buf.Close()

// if rpm sign enabled
if setting.Packages.RPMSignEnabled {
pri, _, err := rpm_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
buf, err = rpm_service.SignPackage(buf, pri)
if err != nil {
// Not in rpm format, parsing failed.
apiError(ctx, http.StatusBadRequest, err)
return
}
}

pck, err := rpm_module.ParsePackage(buf)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
Expand All @@ -142,7 +157,6 @@ func UploadPackageFile(ctx *context.Context) {
}
return
}

if _, err := buf.Seek(0, io.SeekStart); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
Expand Down
45 changes: 45 additions & 0 deletions services/packages/rpm/sign.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package rpm

import (
"bytes"
"io"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/packages"

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/sassoftware/go-rpmutils"
)

func SignPackage(rpm *packages.HashedBuffer, privateKey string) (*packages.HashedBuffer, error) {
keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewReader([]byte(privateKey)))
if err != nil {
// failed to parse key
return nil, err
}
entity := keyring[0]
h, err := rpmutils.SignRpmStream(rpm, entity.PrivateKey, nil)
if err != nil {
// error signing rpm
return nil, err
}
signBlob, err := h.DumpSignatureHeader(false)
if err != nil {
// error writing sig header
return nil, err
}
if len(signBlob)%8 != 0 {
log.Info("incorrect padding: got %d bytes, expected a multiple of 8", len(signBlob))
return nil, err
}

// move fp to sign end
if _, err := rpm.Seek(int64(h.OriginalSignatureHeaderSize()), io.SeekStart); err != nil {
return nil, err
}
// create signed rpm buf
return packages.CreateHashedBufferFromReader(io.MultiReader(bytes.NewReader(signBlob), rpm))
}
72 changes: 72 additions & 0 deletions services/packages/rpm/sign_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package rpm

import (
"bytes"
"compress/gzip"
"encoding/base64"
"io"
"strings"
"testing"

"code.gitea.io/gitea/modules/packages"

"github.com/ProtonMail/go-crypto/openpgp"
"github.com/sassoftware/go-rpmutils"
"github.com/stretchr/testify/assert"
)

func TestSignPackage(t *testing.T) {
base64RpmPackageContent := `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`
rpmPackageContent, err := base64.StdEncoding.DecodeString(base64RpmPackageContent)
assert.NoError(t, err)
zr, err := gzip.NewReader(bytes.NewReader(rpmPackageContent))
assert.NoError(t, err)
content, err := io.ReadAll(zr)
assert.NoError(t, err)
privateKey, publicKey, err := generateKeypair()
assert.NoError(t, err)
buf, err := packages.CreateHashedBufferFromReader(bytes.NewReader(content))
assert.NoError(t, err)
body, err := SignPackage(buf, privateKey)
assert.NoError(t, err)
signedBody, err := io.ReadAll(body)
assert.NoError(t, err)
pub, err := openpgp.ReadArmoredKeyRing(strings.NewReader(publicKey))
assert.NoError(t, err)
_, sigs, err := rpmutils.Verify(bytes.NewBuffer(signedBody), pub)
assert.NoError(t, err)
assert.NotEqual(t, len(sigs), 0)
_, sigs, err = rpmutils.Verify(bytes.NewBuffer(content), pub)
assert.NoError(t, err)
assert.Equal(t, len(sigs), 0)
}
Loading