42
42
import java .util .Optional ;
43
43
import java .util .logging .Level ;
44
44
import java .util .logging .Logger ;
45
+ import java .util .stream .Collectors ;
45
46
import org .bouncycastle .util .encoders .DecoderException ;
46
47
import org .bouncycastle .util .encoders .Hex ;
47
48
@@ -211,8 +212,7 @@ private boolean hasNewKeys(RootRole oldRole, RootRole newRole) {
211
212
}
212
213
213
214
void verifyDelegate (Root trustedRoot , SignedTufMeta <? extends TufMeta > delegate )
214
- throws SignatureVerificationException , IOException , NoSuchAlgorithmException ,
215
- InvalidKeySpecException {
215
+ throws SignatureVerificationException , IOException {
216
216
verifyDelegate (
217
217
delegate .getSignatures (),
218
218
trustedRoot .getSignedMeta ().getKeys (),
@@ -228,23 +228,31 @@ void verifyDelegate(Root trustedRoot, SignedTufMeta<? extends TufMeta> delegate)
228
228
* @param role the key ids and threshold values for role signing
229
229
* @param verificationMaterial the contents to be verified for authenticity
230
230
* @throws SignatureVerificationException if there are not enough verified signatures
231
+ * @throws IOException if an error occurred parsing a key
231
232
*/
232
233
@ VisibleForTesting
233
234
void verifyDelegate (
234
235
List <Signature > signatures ,
235
236
Map <String , Key > publicKeys ,
236
237
Role role ,
237
238
byte [] verificationMaterial )
238
- throws InvalidKeySpecException , IOException , NoSuchAlgorithmException {
239
+ throws IOException {
239
240
// use set to not count the same key multiple times towards the threshold.
240
241
var goodSigs = new HashSet <>(role .getKeyids ().size () * 4 / 3 );
241
242
// role.getKeyIds() defines the keys allowed to sign for this role.
242
243
for (String keyid : role .getKeyids ()) {
243
- Optional <Signature > signatureMaybe =
244
- signatures .stream ().filter (sig -> sig .getKeyId ().equals (keyid )).findFirst ();
244
+ List <Signature > matchingSignatures =
245
+ signatures .stream ()
246
+ .filter (sig -> sig .getKeyId ().equals (keyid ))
247
+ .collect (Collectors .toList ());
248
+ // check for any duplicate key_ids:
249
+ // https://theupdateframework.github.io/specification/latest/#file-formats-object-format
250
+ if (matchingSignatures .size () > 1 ) {
251
+ throw new DuplicateKeyIdsException (matchingSignatures , keyid );
252
+ }
245
253
// only verify if we find a signature that matches an allowed key id.
246
- if (signatureMaybe . isPresent () ) {
247
- var signature = signatureMaybe .get ();
254
+ if (matchingSignatures . size () == 1 ) {
255
+ var signature = matchingSignatures .get (0 );
248
256
// look for the public key that matches the key ID and use it for verification.
249
257
var key = publicKeys .get (signature .getKeyId ());
250
258
if (key != null ) {
0 commit comments