package openpgp_ops import ( "bytes" "crypto" "fmt" "os" "time" log "github.com/sirupsen/logrus" "golang.org/x/crypto/openpgp" "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) { 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) } signatures := make([]*openpgp.Entity, 0) for _, pe := range pubKeyRing { log.Tracef("found %+v", pe) for _, i := range pe.Identities { if !i.SelfSignature.KeyExpired(time.Now()) { signConfig := &packet.Config{ DefaultHash: *algorithm, Time: func() { return calculateExpiry(i, days) }, } pe.SignIdentity(i.Name, signingKey, signConfig) } } } } func calculateExpiry(i *openpgp.Identity, days uint16) time.Time { maxExpiry := i.SelfSignature.CreationTime.Add(time.Second * time.Duration(*i.SelfSignature.KeyLifetimeSecs)) calcExpiry := time.Now().Add(time.Hour * 24 * time.Duration(days)) if calcExpiry.After(maxExpiry) { return maxExpiry } return maxExpiry } 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 %+v", e) 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 }