2021-07-13 16:28:07 +03:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2021-07-13 16:28:07 +03:00
2021-12-10 11:14:24 +03:00
package asymkey
2021-07-13 16:28:07 +03:00
import (
2022-05-20 17:08:52 +03:00
"context"
2021-07-13 16:28:07 +03:00
"strings"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2021-07-13 16:28:07 +03:00
"code.gitea.io/gitea/modules/log"
"github.com/keybase/go-crypto/openpgp"
)
// __________________ ________ ____ __.
// / _____/\______ \/ _____/ | |/ _|____ ___.__.
// / \ ___ | ___/ \ ___ | <_/ __ < | |
// \ \_\ \| | \ \_\ \ | | \ ___/\___ |
// \______ /|____| \______ / |____|__ \___ > ____|
// \/ \/ \/ \/\/
// _____ .___ .___
// / _ \ __| _/__| _/
// / /_\ \ / __ |/ __ |
// / | \/ /_/ / /_/ |
// \____|__ /\____ \____ |
// \/ \/ \/
// This file contains functions relating to adding GPG Keys
// addGPGKey add key, import and subkeys to database
2022-05-20 17:08:52 +03:00
func addGPGKey ( ctx context . Context , key * GPGKey , content string ) ( err error ) {
2021-07-13 16:28:07 +03:00
// Add GPGKeyImport
2022-05-20 17:08:52 +03:00
if err = db . Insert ( ctx , & GPGKeyImport {
2021-07-13 16:28:07 +03:00
KeyID : key . KeyID ,
Content : content ,
} ) ; err != nil {
return err
}
// Save GPG primary key.
2022-05-20 17:08:52 +03:00
if err = db . Insert ( ctx , key ) ; err != nil {
2021-07-13 16:28:07 +03:00
return err
}
// Save GPG subs key.
for _ , subkey := range key . SubsKey {
2022-05-20 17:08:52 +03:00
if err := addGPGSubKey ( ctx , subkey ) ; err != nil {
2021-07-13 16:28:07 +03:00
return err
}
}
return nil
}
// addGPGSubKey add subkeys to database
2022-05-20 17:08:52 +03:00
func addGPGSubKey ( ctx context . Context , key * GPGKey ) ( err error ) {
2021-07-13 16:28:07 +03:00
// Save GPG primary key.
2022-05-20 17:08:52 +03:00
if err = db . Insert ( ctx , key ) ; err != nil {
2021-07-13 16:28:07 +03:00
return err
}
// Save GPG subs key.
for _ , subkey := range key . SubsKey {
2022-05-20 17:08:52 +03:00
if err := addGPGSubKey ( ctx , subkey ) ; err != nil {
2021-07-13 16:28:07 +03:00
return err
}
}
return nil
}
// AddGPGKey adds new public key to database.
2023-09-25 16:17:37 +03:00
func AddGPGKey ( ctx context . Context , ownerID int64 , content , token , signature string ) ( [ ] * GPGKey , error ) {
2021-07-13 16:28:07 +03:00
ekeys , err := checkArmoredGPGKeyString ( content )
if err != nil {
return nil , err
}
2023-09-25 16:17:37 +03:00
ctx , committer , err := db . TxContext ( ctx )
2021-09-19 14:49:59 +03:00
if err != nil {
2021-07-13 16:28:07 +03:00
return nil , err
}
2021-09-19 14:49:59 +03:00
defer committer . Close ( )
2021-07-13 16:28:07 +03:00
keys := make ( [ ] * GPGKey , 0 , len ( ekeys ) )
verified := false
// Handle provided signature
if signature != "" {
signer , err := openpgp . CheckArmoredDetachedSignature ( ekeys , strings . NewReader ( token ) , strings . NewReader ( signature ) )
if err != nil {
signer , err = openpgp . CheckArmoredDetachedSignature ( ekeys , strings . NewReader ( token + "\n" ) , strings . NewReader ( signature ) )
}
if err != nil {
signer , err = openpgp . CheckArmoredDetachedSignature ( ekeys , strings . NewReader ( token + "\r\n" ) , strings . NewReader ( signature ) )
}
if err != nil {
log . Error ( "Unable to validate token signature. Error: %v" , err )
return nil , ErrGPGInvalidTokenSignature {
ID : ekeys [ 0 ] . PrimaryKey . KeyIdString ( ) ,
Wrapped : err ,
}
}
ekeys = [ ] * openpgp . Entity { signer }
verified = true
}
2021-10-07 23:10:14 +03:00
if len ( ekeys ) > 1 {
id2key := map [ string ] * openpgp . Entity { }
newEKeys := make ( [ ] * openpgp . Entity , 0 , len ( ekeys ) )
for _ , ekey := range ekeys {
id := ekey . PrimaryKey . KeyIdString ( )
if original , has := id2key [ id ] ; has {
// Coalesce this with the other one
for _ , subkey := range ekey . Subkeys {
if subkey . PublicKey == nil {
continue
}
found := false
for _ , originalSubkey := range original . Subkeys {
if originalSubkey . PublicKey == nil {
continue
}
if originalSubkey . PublicKey . KeyId == subkey . PublicKey . KeyId {
found = true
break
}
}
if ! found {
original . Subkeys = append ( original . Subkeys , subkey )
}
}
for name , identity := range ekey . Identities {
if _ , has := original . Identities [ name ] ; has {
continue
}
original . Identities [ name ] = identity
}
continue
}
id2key [ id ] = ekey
newEKeys = append ( newEKeys , ekey )
}
ekeys = newEKeys
}
2021-07-13 16:28:07 +03:00
for _ , ekey := range ekeys {
// Key ID cannot be duplicated.
2021-09-23 18:45:36 +03:00
has , err := db . GetEngine ( ctx ) . Where ( "key_id=?" , ekey . PrimaryKey . KeyIdString ( ) ) .
2021-07-13 16:28:07 +03:00
Get ( new ( GPGKey ) )
if err != nil {
return nil , err
} else if has {
return nil , ErrGPGKeyIDAlreadyUsed { ekey . PrimaryKey . KeyIdString ( ) }
}
// Get DB session
2023-09-14 20:09:32 +03:00
key , err := parseGPGKey ( ctx , ownerID , ekey , verified )
2021-07-13 16:28:07 +03:00
if err != nil {
return nil , err
}
2022-05-20 17:08:52 +03:00
if err = addGPGKey ( ctx , key , content ) ; err != nil {
2021-07-13 16:28:07 +03:00
return nil , err
}
keys = append ( keys , key )
}
2021-09-19 14:49:59 +03:00
return keys , committer . Commit ( )
2021-07-13 16:28:07 +03:00
}