code.gitea.io/gitea@v1.22.3/models/asymkey/gpg_key_common.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package asymkey
     5  
     6  import (
     7  	"bytes"
     8  	"crypto"
     9  	"encoding/base64"
    10  	"fmt"
    11  	"hash"
    12  	"io"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/keybase/go-crypto/openpgp"
    17  	"github.com/keybase/go-crypto/openpgp/armor"
    18  	"github.com/keybase/go-crypto/openpgp/packet"
    19  )
    20  
    21  //   __________________  ________   ____  __.
    22  //  /  _____/\______   \/  _____/  |    |/ _|____ ___.__.
    23  // /   \  ___ |     ___/   \  ___  |      <_/ __ <   |  |
    24  // \    \_\  \|    |   \    \_\  \ |    |  \  ___/\___  |
    25  //  \______  /|____|    \______  / |____|__ \___  > ____|
    26  //         \/                  \/          \/   \/\/
    27  // _________
    28  // \_   ___ \  ____   _____   _____   ____   ____
    29  // /    \  \/ /  _ \ /     \ /     \ /  _ \ /    \
    30  // \     \___(  <_> )  Y Y  \  Y Y  (  <_> )   |  \
    31  //  \______  /\____/|__|_|  /__|_|  /\____/|___|  /
    32  //         \/             \/      \/            \/
    33  
    34  // This file provides common functions relating to GPG Keys
    35  
    36  // checkArmoredGPGKeyString checks if the given key string is a valid GPG armored key.
    37  // The function returns the actual public key on success
    38  func checkArmoredGPGKeyString(content string) (openpgp.EntityList, error) {
    39  	list, err := openpgp.ReadArmoredKeyRing(strings.NewReader(content))
    40  	if err != nil {
    41  		return nil, ErrGPGKeyParsing{err}
    42  	}
    43  	return list, nil
    44  }
    45  
    46  // base64EncPubKey encode public key content to base 64
    47  func base64EncPubKey(pubkey *packet.PublicKey) (string, error) {
    48  	var w bytes.Buffer
    49  	err := pubkey.Serialize(&w)
    50  	if err != nil {
    51  		return "", err
    52  	}
    53  	return base64.StdEncoding.EncodeToString(w.Bytes()), nil
    54  }
    55  
    56  func readerFromBase64(s string) (io.Reader, error) {
    57  	bs, err := base64.StdEncoding.DecodeString(s)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	return bytes.NewBuffer(bs), nil
    62  }
    63  
    64  // base64DecPubKey decode public key content from base 64
    65  func base64DecPubKey(content string) (*packet.PublicKey, error) {
    66  	b, err := readerFromBase64(content)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	// Read key
    71  	p, err := packet.Read(b)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	// Check type
    76  	pkey, ok := p.(*packet.PublicKey)
    77  	if !ok {
    78  		return nil, fmt.Errorf("key is not a public key")
    79  	}
    80  	return pkey, nil
    81  }
    82  
    83  // getExpiryTime extract the expire time of primary key based on sig
    84  func getExpiryTime(e *openpgp.Entity) time.Time {
    85  	expiry := time.Time{}
    86  	// Extract self-sign for expire date based on : https://github.com/golang/crypto/blob/master/openpgp/keys.go#L165
    87  	var selfSig *packet.Signature
    88  	for _, ident := range e.Identities {
    89  		if selfSig == nil {
    90  			selfSig = ident.SelfSignature
    91  		} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
    92  			selfSig = ident.SelfSignature
    93  			break
    94  		}
    95  	}
    96  	if selfSig.KeyLifetimeSecs != nil {
    97  		expiry = e.PrimaryKey.CreationTime.Add(time.Duration(*selfSig.KeyLifetimeSecs) * time.Second)
    98  	}
    99  	return expiry
   100  }
   101  
   102  func populateHash(hashFunc crypto.Hash, msg []byte) (hash.Hash, error) {
   103  	h := hashFunc.New()
   104  	if _, err := h.Write(msg); err != nil {
   105  		return nil, err
   106  	}
   107  	return h, nil
   108  }
   109  
   110  // 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
   111  func readArmoredSign(r io.Reader) (body io.Reader, err error) {
   112  	block, err := armor.Decode(r)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if block.Type != openpgp.SignatureType {
   117  		return nil, fmt.Errorf("expected '" + openpgp.SignatureType + "', got: " + block.Type)
   118  	}
   119  	return block.Body, nil
   120  }
   121  
   122  func extractSignature(s string) (*packet.Signature, error) {
   123  	r, err := readArmoredSign(strings.NewReader(s))
   124  	if err != nil {
   125  		return nil, fmt.Errorf("Failed to read signature armor")
   126  	}
   127  	p, err := packet.Read(r)
   128  	if err != nil {
   129  		return nil, fmt.Errorf("Failed to read signature packet")
   130  	}
   131  	sig, ok := p.(*packet.Signature)
   132  	if !ok {
   133  		return nil, fmt.Errorf("Packet is not a signature")
   134  	}
   135  	return sig, nil
   136  }
   137  
   138  func tryGetKeyIDFromSignature(sig *packet.Signature) string {
   139  	if sig.IssuerKeyId != nil && (*sig.IssuerKeyId) != 0 {
   140  		return fmt.Sprintf("%016X", *sig.IssuerKeyId)
   141  	}
   142  	if sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
   143  		return fmt.Sprintf("%016X", sig.IssuerFingerprint[12:20])
   144  	}
   145  	return ""
   146  }