cacert-gosigner/signer/openpgp_ops/operations.go

114 lines
3.1 KiB
Go
Raw Normal View History

package openpgp_ops
2021-01-05 20:25:29 +01:00
import (
"bytes"
"crypto"
"fmt"
"os"
"time"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/armor"
2021-01-05 20:25:29 +01:00
"golang.org/x/crypto/openpgp/packet"
)
type OpenPGPRoot struct {
Name string
SecretKeyRing string
Identifier string
}
func (r *OpenPGPRoot) SignPublicKey(pubKey []byte, algorithm crypto.Hash, days uint16) ([]byte, error) {
2021-01-05 20:25:29 +01:00
signingKey, err := r.findSigningKey(r.Identifier)
if err != nil {
return nil, fmt.Errorf("could not find a signing key matching %s: %v", r.Identifier, err)
}
pubKeyRing, err := openpgp.ReadKeyRing(bytes.NewReader(pubKey))
if err != nil {
return nil, fmt.Errorf("could not read openpgp keyring: %v", err)
}
output := bytes.NewBuffer([]byte{})
armorOutput, err := armor.Encode(output, "PGP PUBLIC KEY BLOCK", map[string]string{})
if err != nil {
return nil, fmt.Errorf("could not create ASCII armor wrapper for openpgp output: %v", err)
}
2021-01-05 20:25:29 +01:00
for _, pe := range pubKeyRing {
log.Tracef("found %+v", pe.PrimaryKey.KeyIdString())
2021-01-05 20:25:29 +01:00
for _, i := range pe.Identities {
expiry := calculateExpiry(i, days)
2021-01-05 20:25:29 +01:00
if !i.SelfSignature.KeyExpired(time.Now()) {
sig := &packet.Signature{
SigType: packet.SigTypeGenericCert,
PubKeyAlgo: signingKey.PrivateKey.PubKeyAlgo,
Hash: algorithm,
CreationTime: time.Now(),
SigLifetimeSecs: expiry,
IssuerKeyId: &signingKey.PrivateKey.KeyId,
2021-01-05 20:25:29 +01:00
}
if err := sig.SignUserId(i.Name, pe.PrimaryKey, signingKey.PrivateKey, &packet.Config{
DefaultHash: algorithm,
}); err != nil {
return nil, fmt.Errorf("could not sign identity %s: %v", i.Name, err)
}
i.Signatures = append(i.Signatures, sig)
2021-01-05 20:25:29 +01:00
}
}
if err = pe.Serialize(armorOutput); err != nil {
return nil, fmt.Errorf(
"could not write signed public key %s to output: %v",
pe.PrimaryKey.KeyIdString(),
err,
)
}
2021-01-05 20:25:29 +01:00
}
if err = armorOutput.Close(); err != nil {
return nil, fmt.Errorf("could not close output stream: %v", err)
}
log.Tracef("signed public key\n%s", output.String())
return output.Bytes(), nil
2021-01-05 20:25:29 +01:00
}
func calculateExpiry(i *openpgp.Identity, days uint16) *uint32 {
maxExpiry := time.Second * time.Duration(*i.SelfSignature.KeyLifetimeSecs)
calcExpiry := time.Hour * 24 * time.Duration(days)
2021-01-05 20:25:29 +01:00
if calcExpiry > maxExpiry {
calcExpiry = maxExpiry
2021-01-05 20:25:29 +01:00
}
expirySeconds := uint32(calcExpiry.Seconds())
return &expirySeconds
2021-01-05 20:25:29 +01:00
}
func (r *OpenPGPRoot) findSigningKey(identifier string) (*openpgp.Entity, error) {
keyring, err := os.Open(r.SecretKeyRing)
if err != nil {
return nil, fmt.Errorf("could not open secret keyring: %v", err)
}
defer func() { _ = keyring.Close() }()
el, err := openpgp.ReadKeyRing(keyring)
if err != nil {
return nil, fmt.Errorf("could not read keyring: %v", err)
}
for _, e := range el {
log.Tracef("found %s", e.PrimaryKey.KeyIdString())
2021-01-05 20:25:29 +01:00
for _, i := range e.Identities {
if i.UserId.Email == identifier && len(e.Revocations) == 0 && !i.SelfSignature.KeyExpired(time.Now()) {
return e, nil
}
}
}
return nil, fmt.Errorf("no matching key found")
}
type OpenPGPProfile struct {
Name string
}