Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/go_modules/github.com/theupdatefr…
Browse files Browse the repository at this point in the history
…amework/go-tuf-0.3.1
  • Loading branch information
rhatdan committed Jul 13, 2022
2 parents 7df0116 + cf6ccb9 commit fa91c4e
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 92 deletions.
3 changes: 2 additions & 1 deletion docs/containers-policy.json.5.md
Expand Up @@ -156,13 +156,14 @@ This requirement requires an image to be signed using “simple signing” with
"type": "signedBy",
"keyType": "GPGKeys", /* The only currently supported value */
"keyPath": "/path/to/local/keyring/file",
"keyPaths": ["/path/to/local/keyring/file1","/path/to/local/keyring/file2"…],
"keyData": "base64-encoded-keyring-data",
"signedIdentity": identity_requirement
}
```
<!-- Later: other keyType values -->

Exactly one of `keyPath` and `keyData` must be present, containing a GPG keyring of one or more public keys. Only signatures made by these keys are accepted.
Exactly one of `keyPath`, `keyPaths` and `keyData` must be present, containing a GPG keyring of one or more public keys. Only signatures made by these keys are accepted.

The `signedIdentity` field, a JSON object, specifies what image identity the signature claims about the image.
One of the following alternatives are supported:
Expand Down
7 changes: 7 additions & 0 deletions signature/fixtures/policy.json
Expand Up @@ -75,6 +75,13 @@
}
}
],
"registry.redhat.io/beta": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPaths": ["/keys/RH-production-signing-key-gpg-keyring", "/keys/RH-beta-signing-key-gpg-keyring"]
}
],
"private-mirror:5000/vendor-mirror": [
{
"type": "signedBy",
Expand Down
Binary file added signature/fixtures/public-key-1.gpg
Binary file not shown.
Binary file added signature/fixtures/public-key-2.gpg
Binary file not shown.
2 changes: 1 addition & 1 deletion signature/mechanism.go
Expand Up @@ -65,7 +65,7 @@ func NewGPGSigningMechanism() (SigningMechanism, error) {
// of these keys.
// The caller must call .Close() on the returned SigningMechanism.
func NewEphemeralGPGSigningMechanism(blob []byte) (SigningMechanism, []string, error) {
return newEphemeralGPGSigningMechanism(blob)
return newEphemeralGPGSigningMechanism([][]byte{blob})
}

// gpgUntrustedSignatureContents returns UNTRUSTED contents of the signature WITHOUT ANY VERIFICATION,
Expand Down
14 changes: 9 additions & 5 deletions signature/mechanism_gpgme.go
Expand Up @@ -33,10 +33,10 @@ func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWith
}

// newEphemeralGPGSigningMechanism returns a new GPG/OpenPGP signing mechanism which
// recognizes _only_ public keys from the supplied blob, and returns the identities
// recognizes _only_ public keys from the supplied blobs, and returns the identities
// of these keys.
// The caller must call .Close() on the returned SigningMechanism.
func newEphemeralGPGSigningMechanism(blob []byte) (signingMechanismWithPassphrase, []string, error) {
func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) {
dir, err := os.MkdirTemp("", "containers-ephemeral-gpg-")
if err != nil {
return nil, nil, err
Expand All @@ -55,9 +55,13 @@ func newEphemeralGPGSigningMechanism(blob []byte) (signingMechanismWithPassphras
ctx: ctx,
ephemeralDir: dir,
}
keyIdentities, err := mech.importKeysFromBytes(blob)
if err != nil {
return nil, nil, err
keyIdentities := []string{}
for _, blob := range blobs {
ki, err := mech.importKeysFromBytes(blob)
if err != nil {
return nil, nil, err
}
keyIdentities = append(keyIdentities, ki...)
}

removeDir = false
Expand Down
13 changes: 9 additions & 4 deletions signature/mechanism_openpgp.go
Expand Up @@ -63,14 +63,19 @@ func newGPGSigningMechanismInDirectory(optionalDir string) (signingMechanismWith
// recognizes _only_ public keys from the supplied blob, and returns the identities
// of these keys.
// The caller must call .Close() on the returned SigningMechanism.
func newEphemeralGPGSigningMechanism(blob []byte) (signingMechanismWithPassphrase, []string, error) {
func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassphrase, []string, error) {
m := &openpgpSigningMechanism{
keyring: openpgp.EntityList{},
}
keyIdentities, err := m.importKeysFromBytes(blob)
if err != nil {
return nil, nil, err
keyIdentities := []string{}
for _, blob := range blobs {
ki, err := m.importKeysFromBytes(blob)
if err != nil {
return nil, nil, err
}
keyIdentities = append(keyIdentities, ki...)
}

return m, keyIdentities, nil
}

Expand Down
12 changes: 11 additions & 1 deletion signature/mechanism_test.go
Expand Up @@ -135,7 +135,7 @@ func TestNewEphemeralGPGSigningMechanism(t *testing.T) {
assert.Equal(t, TestKeyFingerprint, signingFingerprint, version)
}

// Two keys: Read the binary-format pubring.gpg, and concatenate it twice.
// Two keys in a keyring: Read the binary-format pubring.gpg, and concatenate it twice.
// (Using two copies of public-key.gpg, in the ASCII-armored format, works with
// gpgmeSigningMechanism but not openpgpSigningMechanism.)
keyBlob, err = os.ReadFile("./fixtures/pubring.gpg")
Expand All @@ -145,6 +145,16 @@ func TestNewEphemeralGPGSigningMechanism(t *testing.T) {
defer mech.Close()
assert.Equal(t, []string{TestKeyFingerprint, TestKeyFingerprintWithPassphrase, TestKeyFingerprint, TestKeyFingerprintWithPassphrase}, keyIdentities)

// Two keys from two blobs:
keyBlob1, err := os.ReadFile("./fixtures/public-key-1.gpg")
require.NoError(t, err)
keyBlob2, err := os.ReadFile("./fixtures/public-key-2.gpg")
require.NoError(t, err)
mech, keyIdentities, err = newEphemeralGPGSigningMechanism([][]byte{keyBlob1, keyBlob2})
require.NoError(t, err)
defer mech.Close()
assert.Equal(t, []string{TestKeyFingerprint, TestKeyFingerprintWithPassphrase}, keyIdentities)

// Invalid input: This is, sadly, accepted anyway by GPG, just returns no keys.
// For openpgpSigningMechanism we can detect this and fail.
mech, keyIdentities, err = NewEphemeralGPGSigningMechanism([]byte("This is invalid"))
Expand Down
54 changes: 39 additions & 15 deletions signature/policy_config.go
Expand Up @@ -315,12 +315,22 @@ func (pr *prReject) UnmarshalJSON(data []byte) error {
}

// newPRSignedBy returns a new prSignedBy if parameters are valid.
func newPRSignedBy(keyType sbKeyType, keyPath string, keyData []byte, signedIdentity PolicyReferenceMatch) (*prSignedBy, error) {
func newPRSignedBy(keyType sbKeyType, keyPath string, keyPaths []string, keyData []byte, signedIdentity PolicyReferenceMatch) (*prSignedBy, error) {
if !keyType.IsValid() {
return nil, InvalidPolicyFormatError(fmt.Sprintf("invalid keyType \"%s\"", keyType))
}
if len(keyPath) > 0 && len(keyData) > 0 {
return nil, InvalidPolicyFormatError("keyType and keyData cannot be used simultaneously")
keySources := 0
if keyPath != "" {
keySources++
}
if keyPaths != nil {
keySources++
}
if keyData != nil {
keySources++
}
if keySources != 1 {
return nil, InvalidPolicyFormatError("exactly one of keyPath, keyPaths and keyData must be specified")
}
if signedIdentity == nil {
return nil, InvalidPolicyFormatError("signedIdentity not specified")
Expand All @@ -329,24 +339,35 @@ func newPRSignedBy(keyType sbKeyType, keyPath string, keyData []byte, signedIden
prCommon: prCommon{Type: prTypeSignedBy},
KeyType: keyType,
KeyPath: keyPath,
KeyPaths: keyPaths,
KeyData: keyData,
SignedIdentity: signedIdentity,
}, nil
}

// newPRSignedByKeyPath is NewPRSignedByKeyPath, except it returns the private type.
func newPRSignedByKeyPath(keyType sbKeyType, keyPath string, signedIdentity PolicyReferenceMatch) (*prSignedBy, error) {
return newPRSignedBy(keyType, keyPath, nil, signedIdentity)
return newPRSignedBy(keyType, keyPath, nil, nil, signedIdentity)
}

// NewPRSignedByKeyPath returns a new "signedBy" PolicyRequirement using a KeyPath
func NewPRSignedByKeyPath(keyType sbKeyType, keyPath string, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return newPRSignedByKeyPath(keyType, keyPath, signedIdentity)
}

// newPRSignedByKeyPaths is NewPRSignedByKeyPaths, except it returns the private type.
func newPRSignedByKeyPaths(keyType sbKeyType, keyPaths []string, signedIdentity PolicyReferenceMatch) (*prSignedBy, error) {
return newPRSignedBy(keyType, "", keyPaths, nil, signedIdentity)
}

// NewPRSignedByKeyPaths returns a new "signedBy" PolicyRequirement using KeyPaths
func NewPRSignedByKeyPaths(keyType sbKeyType, keyPaths []string, signedIdentity PolicyReferenceMatch) (PolicyRequirement, error) {
return newPRSignedByKeyPaths(keyType, keyPaths, signedIdentity)
}

// newPRSignedByKeyData is NewPRSignedByKeyData, except it returns the private type.
func newPRSignedByKeyData(keyType sbKeyType, keyData []byte, signedIdentity PolicyReferenceMatch) (*prSignedBy, error) {
return newPRSignedBy(keyType, "", keyData, signedIdentity)
return newPRSignedBy(keyType, "", nil, keyData, signedIdentity)
}

// NewPRSignedByKeyData returns a new "signedBy" PolicyRequirement using a KeyData
Expand All @@ -361,7 +382,7 @@ var _ json.Unmarshaler = (*prSignedBy)(nil)
func (pr *prSignedBy) UnmarshalJSON(data []byte) error {
*pr = prSignedBy{}
var tmp prSignedBy
var gotKeyPath, gotKeyData = false, false
var gotKeyPath, gotKeyPaths, gotKeyData = false, false, false
var signedIdentity json.RawMessage
if err := internal.ParanoidUnmarshalJSONObject(data, func(key string) interface{} {
switch key {
Expand All @@ -372,6 +393,9 @@ func (pr *prSignedBy) UnmarshalJSON(data []byte) error {
case "keyPath":
gotKeyPath = true
return &tmp.KeyPath
case "keyPaths":
gotKeyPaths = true
return &tmp.KeyPaths
case "keyData":
gotKeyData = true
return &tmp.KeyData
Expand Down Expand Up @@ -400,16 +424,16 @@ func (pr *prSignedBy) UnmarshalJSON(data []byte) error {
var res *prSignedBy
var err error
switch {
case gotKeyPath && gotKeyData:
return InvalidPolicyFormatError("keyPath and keyData cannot be used simultaneously")
case gotKeyPath && !gotKeyData:
case gotKeyPath && !gotKeyPaths && !gotKeyData:
res, err = newPRSignedByKeyPath(tmp.KeyType, tmp.KeyPath, tmp.SignedIdentity)
case !gotKeyPath && gotKeyData:
case !gotKeyPath && gotKeyPaths && !gotKeyData:
res, err = newPRSignedByKeyPaths(tmp.KeyType, tmp.KeyPaths, tmp.SignedIdentity)
case !gotKeyPath && !gotKeyPaths && gotKeyData:
res, err = newPRSignedByKeyData(tmp.KeyType, tmp.KeyData, tmp.SignedIdentity)
case !gotKeyPath && !gotKeyData:
return InvalidPolicyFormatError("At least one of keyPath and keyData mus be specified")
default: // Coverage: This should never happen
return fmt.Errorf("Impossible keyPath/keyData presence combination!?")
case !gotKeyPath && !gotKeyPaths && !gotKeyData:
return InvalidPolicyFormatError("Exactly one of keyPath, keyPaths and keyData must be specified, none of them present")
default:
return fmt.Errorf("Exactly one of keyPath, keyPaths and keyData must be specified, more than one present")
}
if err != nil {
return err
Expand Down Expand Up @@ -581,7 +605,7 @@ func (pr *prSigstoreSigned) UnmarshalJSON(data []byte) error {
case !gotKeyPath && gotKeyData:
res, err = newPRSigstoreSignedKeyData(tmp.KeyData, tmp.SignedIdentity)
case !gotKeyPath && !gotKeyData:
return InvalidPolicyFormatError("At least one of keyPath and keyData mus be specified")
return InvalidPolicyFormatError("At least one of keyPath and keyData must be specified")
default: // Coverage: This should never happen
return fmt.Errorf("Impossible keyPath/keyData presence combination!?")
}
Expand Down

0 comments on commit fa91c4e

Please sign in to comment.