Skip to content

Commit 9213951

Browse files
committed
Allow addition of gpg keyring with multiple keys
Related go-gitea#6778 Signed-off-by: Andrew Thornton <art27@cantab.net>
1 parent 2ef318e commit 9213951

File tree

4 files changed

+85
-67
lines changed

4 files changed

+85
-67
lines changed

Diff for: models/gpg_key.go

+67-59
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@ func GetGPGImportByKeyID(keyID string) (*GPGKeyImport, error) {
106106

107107
// checkArmoredGPGKeyString checks if the given key string is a valid GPG armored key.
108108
// The function returns the actual public key on success
109-
func checkArmoredGPGKeyString(content string) (*openpgp.Entity, error) {
109+
func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) {
110110
list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content))
111111
if err != nil {
112112
return nil, ErrGPGKeyParsing{err}
113113
}
114-
return list[0], nil
114+
return list, nil
115115
}
116116

117117
//addGPGKey add key, import and subkeys to database
@@ -152,38 +152,40 @@ func addGPGSubKey(e Engine, key *GPGKey) (err error) {
152152
}
153153

154154
// AddGPGKey adds new public key to database.
155-
func AddGPGKey(ownerID int64, content string) (*GPGKey, error) {
156-
ekey, err := checkArmoredGPGKeyString(content)
155+
func AddGPGKey(ownerID int64, content string) ([]*GPGKey, error) {
156+
ekeys, err := checkArmoredGPGKeyString(content)
157157
if err != nil {
158158
return nil, err
159159
}
160-
161-
// Key ID cannot be duplicated.
162-
has, err := x.Where("key_id=?", ekey.PrimaryKey.KeyIdString()).
163-
Get(new(GPGKey))
164-
if err != nil {
165-
return nil, err
166-
} else if has {
167-
return nil, ErrGPGKeyIDAlreadyUsed{ekey.PrimaryKey.KeyIdString()}
168-
}
169-
170-
//Get DB session
171160
sess := x.NewSession()
172161
defer sess.Close()
173162
if err = sess.Begin(); err != nil {
174163
return nil, err
175164
}
165+
keys := make([]*GPGKey, 0, len(ekeys))
166+
for _, ekey := range ekeys {
167+
// Key ID cannot be duplicated.
168+
has, err := sess.Where("key_id=?", ekey.PrimaryKey.KeyIdString()).
169+
Get(new(GPGKey))
170+
if err != nil {
171+
return nil, err
172+
} else if has {
173+
return nil, ErrGPGKeyIDAlreadyUsed{ekey.PrimaryKey.KeyIdString()}
174+
}
176175

177-
key, err := parseGPGKey(ownerID, ekey)
178-
if err != nil {
179-
return nil, err
180-
}
176+
//Get DB session
181177

182-
if err = addGPGKey(sess, key, content); err != nil {
183-
return nil, err
184-
}
178+
key, err := parseGPGKey(ownerID, ekey)
179+
if err != nil {
180+
return nil, err
181+
}
185182

186-
return key, sess.Commit()
183+
if err = addGPGKey(sess, key, content); err != nil {
184+
return nil, err
185+
}
186+
keys = append(keys, key)
187+
}
188+
return keys, sess.Commit()
187189
}
188190

189191
//base64EncPubKey encode public key content to base 64
@@ -221,7 +223,11 @@ func GPGKeyToEntity(k *GPGKey) (*openpgp.Entity, error) {
221223
if err != nil {
222224
return nil, err
223225
}
224-
return checkArmoredGPGKeyString(impKey.Content)
226+
keys, err := checkArmoredGPGKeyString(impKey.Content)
227+
if err != nil {
228+
return nil, err
229+
}
230+
return keys[0], err
225231
}
226232

227233
//parseSubGPGKey parse a sub Key
@@ -758,7 +764,7 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
758764
}
759765

760766
// Otherwise we have to parse the key
761-
ekey, err := checkArmoredGPGKeyString(gpgSettings.PublicKeyContent)
767+
ekeys, err := checkArmoredGPGKeyString(gpgSettings.PublicKeyContent)
762768
if err != nil {
763769
log.Error("Unable to get default signing key: %v", err)
764770
return &CommitVerification{
@@ -767,48 +773,50 @@ func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature,
767773
Reason: "gpg.error.generate_hash",
768774
}
769775
}
770-
pubkey := ekey.PrimaryKey
771-
content, err := base64EncPubKey(pubkey)
772-
if err != nil {
773-
return &CommitVerification{
774-
CommittingUser: committer,
775-
Verified: false,
776-
Reason: "gpg.error.generate_hash",
777-
}
778-
}
779-
k := &GPGKey{
780-
Content: content,
781-
CanSign: pubkey.CanSign(),
782-
KeyID: pubkey.KeyIdString(),
783-
}
784-
for _, subKey := range ekey.Subkeys {
785-
content, err := base64EncPubKey(subKey.PublicKey)
776+
for _, ekey := range ekeys {
777+
pubkey := ekey.PrimaryKey
778+
content, err := base64EncPubKey(pubkey)
786779
if err != nil {
787780
return &CommitVerification{
788781
CommittingUser: committer,
789782
Verified: false,
790783
Reason: "gpg.error.generate_hash",
791784
}
792785
}
793-
k.SubsKey = append(k.SubsKey, &GPGKey{
786+
k := &GPGKey{
794787
Content: content,
795-
CanSign: subKey.PublicKey.CanSign(),
796-
KeyID: subKey.PublicKey.KeyIdString(),
797-
})
798-
}
799-
if commitVerification := hashAndVerifyWithSubKeys(sig, payload, k, committer, &User{
800-
Name: gpgSettings.Name,
801-
Email: gpgSettings.Email,
802-
}, gpgSettings.Email); commitVerification != nil {
803-
return commitVerification
804-
}
805-
if keyID == k.KeyID {
806-
// This is a bad situation ... We have a key id that matches our default key but the signature doesn't match.
807-
return &CommitVerification{
808-
CommittingUser: committer,
809-
Verified: false,
810-
Warning: true,
811-
Reason: BadSignature,
788+
CanSign: pubkey.CanSign(),
789+
KeyID: pubkey.KeyIdString(),
790+
}
791+
for _, subKey := range ekey.Subkeys {
792+
content, err := base64EncPubKey(subKey.PublicKey)
793+
if err != nil {
794+
return &CommitVerification{
795+
CommittingUser: committer,
796+
Verified: false,
797+
Reason: "gpg.error.generate_hash",
798+
}
799+
}
800+
k.SubsKey = append(k.SubsKey, &GPGKey{
801+
Content: content,
802+
CanSign: subKey.PublicKey.CanSign(),
803+
KeyID: subKey.PublicKey.KeyIdString(),
804+
})
805+
}
806+
if commitVerification := hashAndVerifyWithSubKeys(sig, payload, k, committer, &User{
807+
Name: gpgSettings.Name,
808+
Email: gpgSettings.Email,
809+
}, gpgSettings.Email); commitVerification != nil {
810+
return commitVerification
811+
}
812+
if keyID == k.KeyID {
813+
// This is a bad situation ... We have a key id that matches our default key but the signature doesn't match.
814+
return &CommitVerification{
815+
CommittingUser: committer,
816+
Verified: false,
817+
Warning: true,
818+
Reason: BadSignature,
819+
}
812820
}
813821
}
814822
return nil

Diff for: models/gpg_key_test.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ Av844q/BfRuVsJsK1NDNG09LC30B0l3LKBqlrRmRTUMHtgchdX2dY+p7GPOoSzlR
102102
MkM/fdpyc2hY7Dl/+qFmN5MG5yGmMpQcX+RNNR222ibNC1D3wg==
103103
=i9b7
104104
-----END PGP PUBLIC KEY BLOCK-----`
105-
ekey, err := checkArmoredGPGKeyString(testGPGArmor)
105+
keys, err := checkArmoredGPGKeyString(testGPGArmor)
106+
ekey := keys[0]
106107
assert.NoError(t, err, "Could not parse a valid GPG armored key", ekey)
107108

108109
pubkey := ekey.PrimaryKey
@@ -219,9 +220,9 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL
219220
=zHo9
220221
-----END PGP PUBLIC KEY BLOCK-----`
221222

222-
key, err := AddGPGKey(1, testEmailWithUpperCaseLetters)
223+
keys, err := AddGPGKey(1, testEmailWithUpperCaseLetters)
223224
assert.NoError(t, err)
224-
225+
key := keys[0]
225226
if assert.Len(t, key.Emails, 1) {
226227
assert.Equal(t, "user1@example.com", key.Emails[0].Email)
227228
}
@@ -371,8 +372,9 @@ epiDVQ==
371372
=VSKJ
372373
-----END PGP PUBLIC KEY BLOCK-----
373374
`
374-
ekey, err := checkArmoredGPGKeyString(testIssue6599)
375+
keys, err := checkArmoredGPGKeyString(testIssue6599)
375376
assert.NoError(t, err)
377+
ekey := keys[0]
376378
expire := getExpiryTime(ekey)
377379
assert.Equal(t, time.Unix(1586105389, 0), expire)
378380
}

Diff for: routers/api/v1/user/gpg_key.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ func GetGPGKey(ctx *context.APIContext) {
118118

119119
// CreateUserGPGKey creates new GPG key to given user by ID.
120120
func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) {
121-
key, err := models.AddGPGKey(uid, form.ArmoredKey)
121+
keys, err := models.AddGPGKey(uid, form.ArmoredKey)
122122
if err != nil {
123123
HandleAddGPGKeyError(ctx, err)
124124
return
125125
}
126-
ctx.JSON(http.StatusCreated, convert.ToGPGKey(key))
126+
ctx.JSON(http.StatusCreated, convert.ToGPGKey(keys[0]))
127127
}
128128

129129
// swagger:parameters userCurrentPostGPGKey

Diff for: routers/user/setting/keys.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func KeysPost(ctx *context.Context, form auth.AddKeyForm) {
4141
}
4242
switch form.Type {
4343
case "gpg":
44-
key, err := models.AddGPGKey(ctx.User.ID, form.Content)
44+
keys, err := models.AddGPGKey(ctx.User.ID, form.Content)
4545
if err != nil {
4646
ctx.Data["HasGPGError"] = true
4747
switch {
@@ -63,7 +63,15 @@ func KeysPost(ctx *context.Context, form auth.AddKeyForm) {
6363
}
6464
return
6565
}
66-
ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", key.KeyID))
66+
keyIDs := ""
67+
for _, key := range keys {
68+
keyIDs += key.KeyID
69+
keyIDs += ", "
70+
}
71+
if len(keyIDs) > 0 {
72+
keyIDs = keyIDs[:len(keyIDs)-2]
73+
}
74+
ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
6775
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
6876
case "ssh":
6977
content, err := models.CheckPublicKeyString(form.Content)

0 commit comments

Comments
 (0)