docs/tuf/signed/sign.go

84 lines
2.4 KiB
Go

package signed
// The Sign function is a choke point for all code paths that do signing.
// We use this fact to do key ID translation. There are 2 types of key ID:
// - Scoped: the key ID based purely on the data that appears in the TUF
// files. This may be wrapped by a certificate that scopes the
// key to be used in a specific context.
// - Canonical: the key ID based purely on the public key bytes. This is
// used by keystores to easily identify keys that may be reused
// in many scoped locations.
// Currently these types only differ in the context of Root Keys in Notary
// for which the root key is wrapped using an x509 certificate.
import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/docker/notary/tuf/data"
"github.com/docker/notary/tuf/utils"
)
type idPair struct {
scopedKeyID string
canonicalKeyID string
}
// Sign takes a data.Signed and a key, calculated and adds the signature
// to the data.Signed
func Sign(service CryptoService, s *data.Signed, keys ...data.PublicKey) error {
logrus.Debugf("sign called with %d keys", len(keys))
signatures := make([]data.Signature, 0, len(s.Signatures)+1)
keyIDMemb := make(map[string]struct{})
keyIDs := make(
[]idPair,
0,
len(keys),
)
for _, key := range keys {
keyID, err := utils.CanonicalKeyID(key)
if err != nil {
continue
}
keyIDMemb[key.ID()] = struct{}{}
keyIDs = append(keyIDs, idPair{
scopedKeyID: key.ID(),
canonicalKeyID: keyID,
})
}
// we need to ask the signer to sign with the canonical key ID
// (ID of the TUF key's public key bytes only), but
// we need to translate back to the scoped key ID (the hash of the TUF key
// with the full PEM bytes) before giving the
// signature back to TUF.
for _, pair := range keyIDs {
newSigs, err := service.Sign([]string{pair.canonicalKeyID}, s.Signed)
if err != nil {
return err
}
// we only asked to sign with 1 key ID, so there will either be 1
// or zero signatures
if len(newSigs) == 1 {
newSig := newSigs[0]
newSig.KeyID = pair.scopedKeyID
signatures = append(signatures, newSig)
}
}
if len(signatures) < 1 {
return ErrInsufficientSignatures{
Name: fmt.Sprintf("Cryptoservice failed to produce any signatures for keys with IDs: %v", keyIDs),
Err: nil,
}
}
for _, sig := range s.Signatures {
if _, ok := keyIDMemb[sig.KeyID]; ok {
continue
}
signatures = append(signatures, sig)
}
s.Signatures = signatures
return nil
}