diff --git a/docs/validators/notaryv1.md b/docs/validators/notaryv1.md index ef7d73eec..083678735 100644 --- a/docs/validators/notaryv1.md +++ b/docs/validators/notaryv1.md @@ -182,7 +182,7 @@ For more information on TUF roles, please refer to [TUF's documentation](https:/ | `name` | - | :heavy_check_mark: | See [basics](../basics.md#validators). | | `type` | - | :heavy_check_mark: | `notaryv1`; the validator type must be set to `notaryv1`. | | `host` | - | :heavy_check_mark: | URL of the Notary instance, in which the signatures reside, e.g. `notary.docker.io`. | -| `trustRoots[*].name` | - | :heavy_check_mark: | See [basics](../basics.md#validators). Name of validator for reference in policy section. | +| `trustRoots[*].name` | - | :heavy_check_mark: | See [basics](../basics.md#validators). Setting the name of trust root to "*" implements a logical `and` and enables multiple signature verification under any trust root in the validator. | | `trustRoots[*].key` | - | :heavy_check_mark: | See [basics](../basics.md#validators). TUF public root key. | | `auth` | - | - | Authentication credentials for the Notary server in case the trust data is not public. | | `auth.secretName` | - | - | (Preferred over `username` + `password` combination.) Name of a Kubernetes secret that must exist in Connaisseur namespace beforehand. Create a file `auth.yaml` containing:
  `username: `
  `password: `
Run `kubectl create secret generic --from-file auth.yaml -n connaisseur` to create the secret.| diff --git a/internal/validator/notaryv1/notaryserver/repo.go b/internal/validator/notaryv1/notaryserver/repo.go index 7b3314b05..0128283f9 100644 --- a/internal/validator/notaryv1/notaryserver/repo.go +++ b/internal/validator/notaryv1/notaryserver/repo.go @@ -101,27 +101,23 @@ func (r *Repo) validateRoot(keys []data.PublicKey) error { return fmt.Errorf("no signatures found for root") } - // verify signatures - // it's not expected to have multiple signatures on the root, but we'll check them all - // with all selected keys. - for _, sig := range r.Root.Signatures { - // reassign variable sig to inner variant to prevent possible implicit memory aliasing - sig := sig - errors := []error{} - - // for each signature, verify that at least one keys validates the signature - for _, key := range keys { + // for each key, verify that at least one signature is valid + for _, key := range keys { + verified := false + + for _, sig := range r.Root.Signatures { + sig := sig logrus.Debugf("verifying root signature with key %s", key.ID()) + if err = signed.VerifySignature(msg, &sig, key); err == nil && sig.IsValid { logrus.Debugf("root signature verified with key %s", key.ID()) + verified = true break } - errors = append(errors, err) - logrus.Debugf("root signature failed with key %s", key.ID()) } - if err != nil || !sig.IsValid { - return fmt.Errorf("error validating root signature: %+q", errors) + if !verified { + return fmt.Errorf("error validating root signature with key %s: %s", key.ID(), err) } } diff --git a/internal/validator/notaryv1/notaryserver/repo_test.go b/internal/validator/notaryv1/notaryserver/repo_test.go index f74cfc9d3..b88a27d43 100644 --- a/internal/validator/notaryv1/notaryserver/repo_test.go +++ b/internal/validator/notaryv1/notaryserver/repo_test.go @@ -147,29 +147,29 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUaqgujac1VCdaGHKQMKoDn6/deWJ "root trust data expired", }, { // 4 - "sample-image/root", + "07_root_multiple_signatures", []string{ `-----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtR5kwrDK22SyCu7WMF8tCjVgeORA -S2PWacRcBN/VQdVK4PVk1w4pMWlz9AHQthDGl+W2k3elHkPbR+gNkK2PCA== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUaqgujac1VCdaGHKQMKoDn6/deWJ +8cCzsnDqGDgjPBayhJCQiI/qN+iBWEUPM7BkrCyDS878h+qd/MdZS22XwA== -----END PUBLIC KEY-----`, `-----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvtc/qpHtx7iUUj+rRHR99a8mnGni -qiGkmUb9YpWWTS4YwlvwdmMDiGzcsHiDOYz6f88u2hCRF5GUCvyiZAKrsA== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnsF6hghdCI5MUEEge8PqtSe1HB3O +88lEztfMO+LaUBCyX1aoeB36MrkqeM4zrWe2UUSxFuL6y/+qiPQQQ/n7Ww== -----END PUBLIC KEY-----`, }, "", }, { // 5 - "sample-image/root", + "07_root_multiple_signatures", []string{ `-----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEvtc/qpHtx7iUUj+rRHR99a8mnGni -qiGkmUb9YpWWTS4YwlvwdmMDiGzcsHiDOYz6f88u2hCRF5GUCvyiZAKrsA== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnsF6hghdCI5MUEEge8PqtSe1HB3O +88lEztfMO+LaUBCyX1aoeB36MrkqeM4zrWe2UUSxFuL6y/+qiPQQQ/n7Ww== -----END PUBLIC KEY-----`, `-----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEtR5kwrDK22SyCu7WMF8tCjVgeORA -S2PWacRcBN/VQdVK4PVk1w4pMWlz9AHQthDGl+W2k3elHkPbR+gNkK2PCA== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUaqgujac1VCdaGHKQMKoDn6/deWJ +8cCzsnDqGDgjPBayhJCQiI/qN+iBWEUPM7BkrCyDS878h+qd/MdZS22XwA== -----END PUBLIC KEY-----`, }, "", diff --git a/test/testdata/notaryv1/trust_data/07_root_multiple_signatures.json b/test/testdata/notaryv1/trust_data/07_root_multiple_signatures.json new file mode 100644 index 000000000..d62c90af4 --- /dev/null +++ b/test/testdata/notaryv1/trust_data/07_root_multiple_signatures.json @@ -0,0 +1,76 @@ +{ + "signed": { + "_type": "Root", + "consistent_snapshot": false, + "expires": "2999-08-26T14:12:13.21926558+02:00", + "keys": { + "52e8085cd75be93c5062130e08663a83a20f2eb9baf31f28eef4735e50f3a407": { + "keytype": "ecdsa-x509", + "keyval": { + "private": null, + "public": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ5akNDQVcrZ0F3SUJBZ0lVZnNnNXJ2THhSNkE1TUxLdFgrUE5lN0FoUDhJd0NnWUlLb1pJemowRUF3SXcKT1RFWk1CY0dBMVVFQXd3UWMyVmpkWEpsYzNsemRHVnRjeTVrWlRFTE1Ba0dBMVVFQmhNQ1JFVXhEekFOQmdOVgpCQWNNQmtKbGNteHBiakFnRncweU16QTRNVEV3T1RRM01EQmFHQTh5T1RrNE1EUXlNVEE1TkRjd01Gb3dPVEVaCk1CY0dBMVVFQXd3UWMyVmpkWEpsYzNsemRHVnRjeTVrWlRFTE1Ba0dBMVVFQmhNQ1JFVXhEekFOQmdOVkJBY00KQmtKbGNteHBiakJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCRkdxb0xvMm5OVlFuV2hoeWtEQwpxQTUrdjNYbGlmSEFzN0p3NmhnNEl6d1dzb1NRa0lpUDZqZm9nVmhGRHpPd1pLd3NnMHZPL0lmcW5mekhXVXR0Cmw4Q2pVekJSTUIwR0ExVWREZ1FXQkJUUTNKaTFlbUU4K2wweGVLMzIvNHR0eUF6WU1qQWZCZ05WSFNNRUdEQVcKZ0JUUTNKaTFlbUU4K2wweGVLMzIvNHR0eUF6WU1qQVBCZ05WSFJNQkFmOEVCVEFEQVFIL01Bb0dDQ3FHU000OQpCQU1DQTBrQU1FWUNJUUMvSVQ3VUNxOTBHbExiV2N6SWNwN3Nod0F0WFE3Nlg3R1FHR2lNbmpCb1R3SWhBUGw3Cll5b0JtOGliSzU2cFRycGkraS9CUXlRbEtTT1pSMXZCZWxmVFJnanoKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" + } + }, + "56ec6c5e5d48b72a26289a3230e78ffc4805f7ef74debb8fe2ad567166f51bb8": { + "keytype": "ecdsa", + "keyval": { + "private": null, + "public": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEADZhwhf3fEcDYMRZZFGfQL7cRcbWMqKmaygKpi0RAdw/3cmTjwm8/c71FTbPqPTnbUKFBVDBpxCpsx8SiIcuFg==" + } + }, + "7dc6224e24d6ce2b4260f138e4eff12645aa675b727722aebf86a3421530d886": { + "keytype": "ecdsa", + "keyval": { + "private": null, + "public": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEugAZDGWouB+x8W2J3dnOFMez4vijx4PgtREVwbp3NZvLYZSWd5NJwkBioDWiZITIpWVNQSLosqDNJ1xgSAF7bg==" + } + }, + "d0cef4ea6349fcfbb961a917342a8c218126ebc7eba7ca4351812200207f4f18": { + "keytype": "ecdsa", + "keyval": { + "private": null, + "public": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnsF6hghdCI5MUEEge8PqtSe1HB3O88lEztfMO+LaUBCyX1aoeB36MrkqeM4zrWe2UUSxFuL6y/+qiPQQQ/n7Ww==" + } + } + }, + "roles": { + "root": { + "keyids": [ + "52e8085cd75be93c5062130e08663a83a20f2eb9baf31f28eef4735e50f3a407" + ], + "threshold": 1 + }, + "snapshot": { + "keyids": [ + "56ec6c5e5d48b72a26289a3230e78ffc4805f7ef74debb8fe2ad567166f51bb8" + ], + "threshold": 1 + }, + "targets": { + "keyids": [ + "d0cef4ea6349fcfbb961a917342a8c218126ebc7eba7ca4351812200207f4f18" + ], + "threshold": 1 + }, + "timestamp": { + "keyids": [ + "7dc6224e24d6ce2b4260f138e4eff12645aa675b727722aebf86a3421530d886" + ], + "threshold": 1 + } + }, + "version": 1 + }, + "signatures": [ + { + "keyid": "52e8085cd75be93c5062130e08663a83a20f2eb9baf31f28eef4735e50f3a407", + "method": "ecdsa", + "sig": "1NVDZSAph52T4lljxo5HXpmeiK76CM8B3pb1exJdnnqCcxR9z2wQgHR1P6PQOK7ITRcnRePjjmD4uyRBOHoJIw==" + }, + { + "keyid": "d0cef4ea6349fcfbb961a917342a8c218126ebc7eba7ca4351812200207f4f18", + "method": "ecdsa", + "sig": "bHbVeHquTdZINHXvMl2rRqQY2uYQ/h4U5VesuHT3M7CkV7HrUaU/9pbsEBAR2wQSF0+Q9dvWRgUFVGDw2LvgSg==" + } + ] +}