diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-18 20:33:49 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-12 23:57:56 +0100 |
commit | e68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch) | |
tree | 97775d6c13b0f416af55314eb6a89ef792474615 /models/asymkey/gpg_key_common.go | |
parent | Initial commit. (diff) | |
download | forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip |
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'models/asymkey/gpg_key_common.go')
-rw-r--r-- | models/asymkey/gpg_key_common.go | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/models/asymkey/gpg_key_common.go b/models/asymkey/gpg_key_common.go new file mode 100644 index 0000000..db1912c --- /dev/null +++ b/models/asymkey/gpg_key_common.go @@ -0,0 +1,146 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package asymkey + +import ( + "bytes" + "crypto" + "encoding/base64" + "fmt" + "hash" + "io" + "strings" + "time" + + "github.com/ProtonMail/go-crypto/openpgp" + "github.com/ProtonMail/go-crypto/openpgp/armor" + "github.com/ProtonMail/go-crypto/openpgp/packet" +) + +// __________________ ________ ____ __. +// / _____/\______ \/ _____/ | |/ _|____ ___.__. +// / \ ___ | ___/ \ ___ | <_/ __ < | | +// \ \_\ \| | \ \_\ \ | | \ ___/\___ | +// \______ /|____| \______ / |____|__ \___ > ____| +// \/ \/ \/ \/\/ +// _________ +// \_ ___ \ ____ _____ _____ ____ ____ +// / \ \/ / _ \ / \ / \ / _ \ / \ +// \ \___( <_> ) Y Y \ Y Y ( <_> ) | \ +// \______ /\____/|__|_| /__|_| /\____/|___| / +// \/ \/ \/ \/ + +// This file provides common functions relating to GPG Keys + +// checkArmoredGPGKeyString checks if the given key string is a valid GPG armored key. +// The function returns the actual public key on success +func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) { + list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content)) + if err != nil { + return nil, ErrGPGKeyParsing{err} + } + return list, nil +} + +// base64EncPubKey encode public key content to base 64 +func base64EncPubKey(pubkey *packet.PublicKey) (string, error) { + var w bytes.Buffer + err := pubkey.Serialize(&w) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(w.Bytes()), nil +} + +func readerFromBase64(s string) (io.Reader, error) { + bs, err := base64.StdEncoding.DecodeString(s) + if err != nil { + return nil, err + } + return bytes.NewBuffer(bs), nil +} + +// base64DecPubKey decode public key content from base 64 +func base64DecPubKey(content string) (*packet.PublicKey, error) { + b, err := readerFromBase64(content) + if err != nil { + return nil, err + } + // Read key + p, err := packet.Read(b) + if err != nil { + return nil, err + } + // Check type + pkey, ok := p.(*packet.PublicKey) + if !ok { + return nil, fmt.Errorf("key is not a public key") + } + return pkey, nil +} + +// getExpiryTime extract the expire time of primary key based on sig +func getExpiryTime(e *openpgp.Entity) time.Time { + expiry := time.Time{} + // Extract self-sign for expire date based on : https://github.com/golang/crypto/blob/master/openpgp/keys.go#L165 + var selfSig *packet.Signature + for _, ident := range e.Identities { + if selfSig == nil { + selfSig = ident.SelfSignature + } else if ident.SelfSignature != nil && ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId { + selfSig = ident.SelfSignature + break + } + } + if selfSig.KeyLifetimeSecs != nil { + expiry = e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second) + } + return expiry +} + +func populateHash(hashFunc crypto.Hash, msg []byte) (hash.Hash, error) { + h := hashFunc.New() + if _, err := h.Write(msg); err != nil { + return nil, err + } + return h, nil +} + +// readArmoredSign read an armored signature block with the given type. https://sourcegraph.com/github.com/golang/crypto/-/blob/openpgp/read.go#L24:6-24:17 +func readArmoredSign(r io.Reader) (body io.Reader, err error) { + block, err := armor.Decode(r) + if err != nil { + return nil, err + } + if block.Type != openpgp.SignatureType { + return nil, fmt.Errorf("expected %q, got: %s", openpgp.SignatureType, block.Type) + } + return block.Body, nil +} + +func extractSignature(s string) (*packet.Signature, error) { + r, err := readArmoredSign(strings.NewReader(s)) + if err != nil { + return nil, fmt.Errorf("Failed to read signature armor") + } + p, err := packet.Read(r) + if err != nil { + return nil, fmt.Errorf("Failed to read signature packet") + } + sig, ok := p.(*packet.Signature) + if !ok { + return nil, fmt.Errorf("Packet is not a signature") + } + return sig, nil +} + +func tryGetKeyIDFromSignature(sig *packet.Signature) string { + if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 { + return fmt.Sprintf("%016X", *sig.IssuerKeyId) + } + if len(sig.IssuerFingerprint) > 0 { + return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20]) + } + return "" +} |