From 6cd132b3f747cd1fd7d9bf89e24f982e65cfda6f Mon Sep 17 00:00:00 2001 From: Jan Dittberner Date: Fri, 8 Jan 2021 10:14:11 +0100 Subject: [PATCH] Finish implementation of openpgp signing --- go.mod | 2 ++ go.sum | 6 ++-- signer/command_processor.go | 2 +- signer/openpgp_ops/operations.go | 59 ++++++++++++++++++++++++-------- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index ff30578..c029a7c 100644 --- a/go.mod +++ b/go.mod @@ -9,3 +9,5 @@ require ( golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 gopkg.in/yaml.v2 v2.4.0 ) + +replace golang.org/x/crypto => github.com/jandd/crypto v0.0.0-20210106144236-c3a8dd255ad6 diff --git a/go.sum b/go.sum index 48a8658..e02ce14 100644 --- a/go.sum +++ b/go.sum @@ -3,6 +3,8 @@ github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglD github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jandd/crypto v0.0.0-20210106144236-c3a8dd255ad6 h1:CfOE6Sr6BvfT6R90AgKcospJGP5+hwYhOjFR1XVb68Q= +github.com/jandd/crypto v0.0.0-20210106144236-c3a8dd255ad6/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= @@ -15,11 +17,7 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= go.bug.st/serial v1.1.1 h1:5J1DpaIaSIruBi7jVnKXnhRS+YQ9+2PLJMtIZKoIgnc= go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/signer/command_processor.go b/signer/command_processor.go index a479e31..a8465cd 100644 --- a/signer/command_processor.go +++ b/signer/command_processor.go @@ -312,7 +312,7 @@ func (p *CommandProcessor) signX509Certificate(system *IdSystemParameters, days func (p *CommandProcessor) signOpenpgpKey(system *IdSystemParameters, days uint16, pubKey []byte) ([]byte, error) { openPgpRoot := system.Root.(*openpgp_ops.OpenPGPRoot) - signatureAlgorithm := system.MessageDigestAlgorithm.(*crypto.Hash) + signatureAlgorithm := system.MessageDigestAlgorithm.(crypto.Hash) log.Debugf("sign openpgp for root %s", openPgpRoot) diff --git a/signer/openpgp_ops/operations.go b/signer/openpgp_ops/operations.go index cd6352e..e7f2ce6 100644 --- a/signer/openpgp_ops/operations.go +++ b/signer/openpgp_ops/operations.go @@ -9,6 +9,7 @@ import ( log "github.com/sirupsen/logrus" "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/armor" "golang.org/x/crypto/openpgp/packet" ) @@ -18,7 +19,7 @@ type OpenPGPRoot struct { Identifier string } -func (r *OpenPGPRoot) SignPublicKey(pubKey []byte, algorithm *crypto.Hash, days uint16) ([]byte, error) { +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) @@ -29,30 +30,60 @@ func (r *OpenPGPRoot) SignPublicKey(pubKey []byte, algorithm *crypto.Hash, days return nil, fmt.Errorf("could not read openpgp keyring: %v", err) } - signatures := make([]*openpgp.Entity, 0) + 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) + } for _, pe := range pubKeyRing { - log.Tracef("found %+v", pe) + log.Tracef("found %+v", pe.PrimaryKey.KeyIdString()) for _, i := range pe.Identities { + expiry := calculateExpiry(i, days) if !i.SelfSignature.KeyExpired(time.Now()) { - signConfig := &packet.Config{ - DefaultHash: *algorithm, - Time: func() { return calculateExpiry(i, days) }, + sig := &packet.Signature{ + SigType: packet.SigTypeGenericCert, + PubKeyAlgo: signingKey.PrivateKey.PubKeyAlgo, + Hash: algorithm, + CreationTime: time.Now(), + SigLifetimeSecs: expiry, + IssuerKeyId: &signingKey.PrivateKey.KeyId, } - pe.SignIdentity(i.Name, signingKey, signConfig) + 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) } } + 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, + ) + } } + + 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 } -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)) +func calculateExpiry(i *openpgp.Identity, days uint16) *uint32 { + maxExpiry := time.Second * time.Duration(*i.SelfSignature.KeyLifetimeSecs) + calcExpiry := time.Hour * 24 * time.Duration(days) - if calcExpiry.After(maxExpiry) { - return maxExpiry + if calcExpiry > maxExpiry { + calcExpiry = maxExpiry } - return maxExpiry + expirySeconds := uint32(calcExpiry.Seconds()) + return &expirySeconds } func (r *OpenPGPRoot) findSigningKey(identifier string) (*openpgp.Entity, error) { @@ -67,7 +98,7 @@ func (r *OpenPGPRoot) findSigningKey(identifier string) (*openpgp.Entity, error) return nil, fmt.Errorf("could not read keyring: %v", err) } for _, e := range el { - log.Tracef("found %+v", e) + log.Tracef("found %s", e.PrimaryKey.KeyIdString()) for _, i := range e.Identities { if i.UserId.Email == identifier && len(e.Revocations) == 0 && !i.SelfSignature.KeyExpired(time.Now()) { return e, nil