TrustAnchorValidationService { public void validate(long trustAnchorId) { Optional<TrustAnchor> maybeTrustAnchor = storage.readTx(tx -> trustAnchors.get(tx, Key.of(trustAnchorId))); if (!maybeTrustAnchor.isPresent()) { log.error("Trust anchor {} doesn't exist.", trustAnchorId); return; } TrustAnchor trustAnchor = maybeTrustAnchor.get(); log.info("trust anchor {} located at {} with subject public key info {}", trustAnchor.getName(), trustAnchor.getLocations(), trustAnchor.getSubjectPublicKeyInfo()); TrustAnchorValidationRun validationRun = storage.readTx(tx -> { final Ref<TrustAnchor> trustAnchorRef = trustAnchors.makeRef(tx, Key.of(trustAnchorId)); return new TrustAnchorValidationRun(trustAnchorRef, trustAnchor.getLocations().get(0)); }); final ValidationLocation trustAnchorValidationLocation = new ValidationLocation(validationRun.getTrustAnchorCertificateURI()); ValidationResult validationResult = newValidationResult(trustAnchorValidationLocation); boolean updatedTrustAnchor = false; try { final Optional<Tuple2<URI, byte[]>> maybeTrustAnchorCertificate = fetchPreferredTrustAnchorCertificate(trustAnchor, validationResult); if (maybeTrustAnchorCertificate.isPresent()) { final Tuple2<URI, byte[]> res = maybeTrustAnchorCertificate.get(); updatedTrustAnchor = readTrustAnchorFromLocation(res.v2, trustAnchor, res.v1, validationResult); } else { validationResult.error( ErrorCodes.TRUST_ANCHOR_FETCH, "any location", String.format("None of the locations (%s) could be loaded.", Joiner.on(", ").join(trustAnchor.getLocations()))); validationRun.setFailed(); } if (validationResult.hasFailures()) { log.warn("Validation result for the TA {} has failures: {}", trustAnchor.getName(), validationResult.getFailuresForAllLocations()); } if (trustAnchor.getRsyncPrefetchUri() != null) { storage.writeTx0(tx -> { final Ref<TrustAnchor> trustAnchorRef = trustAnchors.makeRef(tx, trustAnchor.key()); rpkiRepositories.register(tx, trustAnchorRef, trustAnchor.getRsyncPrefetchUri(), RpkiRepository.Type.RSYNC_PREFETCH); }); } validationRun.completeWith(validationResult); if (!validatedAtLeastOnce.contains(trustAnchor.getId()) || updatedTrustAnchor) { if (updatedTrustAnchor) { storage.writeTx0(tx -> trustAnchors.update(tx, trustAnchor)); } final Set<TrustAnchor> affectedTrustAnchors = Sets.newHashSet(trustAnchor); if (trustAnchor.getRsyncPrefetchUri() != null) { storage.readTx(tx -> rpkiRepositories.findByURI(tx, trustAnchor.getRsyncPrefetchUri())) .ifPresent(r -> affectedTrustAnchors.addAll(repositoryValidationService.prefetchRepository(r))); } affectedTrustAnchors.forEach(validationScheduler::triggerCertificateTreeValidation); } } catch (CommandExecutionException | IOException e) { log.error("validation run for trust anchor {} failed", trustAnchor, e); validationRun.addCheck(new ValidationCheck(validationRun.getTrustAnchorCertificateURI(), ValidationCheck.Status.ERROR, ErrorCodes.UNHANDLED_EXCEPTION, e.toString())); validationRun.setFailed(); } finally { validatedAtLeastOnce.add(trustAnchor.getId()); storage.writeTx0(tx -> validationRuns.add(tx, validationRun)); } } @Autowired  TrustAnchorValidationService(
        TrustAnchors trustAnchors,
        RpkiRepositories rpkiRepositories,
        ValidationRuns validationRuns,
        ValidationScheduler validationScheduler,
        RpkiRepositoryValidationService repositoryValidationService,
        Storage storage,
        TrustAnchorMetricsService trustAnchorMetricsService,
        TrustAnchorRetrievalService trustAnchorRetrievalService); void validate(long trustAnchorId); Optional<Tuple2<URI, byte[]>> fetchPreferredTrustAnchorCertificate(TrustAnchor trustAnchor, ValidationResult validationResult);  }
@Test public void test_success() throws IOException { TrustAnchor ta = createRipeNccTrustAnchor(); wtx0(tx -> trustAnchors.add(tx, ta)); ta.setLocations(ImmutableList.of(new ClassPathResource("ripe-ncc-ta.cer").getURI().toString())); subject.validate(ta.key().asLong()); X509ResourceCertificate certificate = rtx(tx -> trustAnchors.get(tx, ta.key()).get().getCertificate()); assertThat(certificate).isNotNull(); Optional<TrustAnchorValidationRun> validationRun = rtx(tx -> validationRuns.findLatestCompletedForTrustAnchor(tx, ta)); assertThat(validationRun).isPresent(); assertThat(validationRun.get().getStatus()).isEqualTo(ValidationRun.Status.SUCCEEDED); assertThat(validationRun.get().getValidationChecks()).isEmpty(); }
@Test public void test_rsync_failure() { TrustAnchor ta = createRipeNccTrustAnchor(); ta.setLocations(ImmutableList.of(DUMMY_RSYNC_URI)); wtx0(tx -> trustAnchors.add(tx, ta)); subject.validate(ta.key().asLong()); assertThat(ta.getCertificate()).isNull(); Optional<TrustAnchorValidationRun> validationRun = rtx(tx -> validationRuns.findLatestCompletedForTrustAnchor(tx, ta)); assertThat(validationRun).isPresent(); List<ValidationCheck> validationChecks = validationRun.get().getValidationChecks(); assertThat(validationChecks).hasSize(2); assertThat(validationChecks).anyMatch(vc -> vc.getKey().equals(ErrorCodes.RSYNC_FETCH)); assertThat(validationChecks).anyMatch(vc -> vc.getKey().equals(ErrorCodes.TRUST_ANCHOR_FETCH)); }
@Test public void test_empty_file() throws IOException { TrustAnchor ta = createRipeNccTrustAnchor(); wtx0(tx -> trustAnchors.add(tx, ta)); ta.setLocations(ImmutableList.of(new ClassPathResource("empty-file.cer").getURI().toString())); wtx0(tx -> trustAnchors.update(tx, ta)); subject.validate(ta.key().asLong()); X509ResourceCertificate certificate = rtx(tx -> trustAnchors.get(tx, ta.key()).get().getCertificate()); assertThat(certificate).isNull(); Optional<TrustAnchorValidationRun> validationRun = rtx(tx -> validationRuns.findLatestCompletedForTrustAnchor(tx, ta)); assertThat(validationRun).isPresent(); List<ValidationCheck> validationChecks = validationRun.get().getValidationChecks(); assertThat(validationChecks).hasSize(1); assertThat(validationChecks.get(0).getKey()).isEqualTo(ErrorCodes.REPOSITORY_OBJECT_MINIMUM_SIZE); }
@Test public void test_bad_subject_public_key() { TrustAnchor ta = createRipeNccTrustAnchor(); ta.setSubjectPublicKeyInfo(ta.getSubjectPublicKeyInfo().toUpperCase()); wtx0(tx -> trustAnchors.add(tx, ta)); ta.setLocations(ImmutableList.of("src/test/resources/ripe-ncc-ta.cer")); subject.validate(ta.key().asLong()); assertThat(ta.getCertificate()).isNull(); Optional<TrustAnchorValidationRun> validationRun = rtx(tx -> validationRuns.findLatestCompletedForTrustAnchor(tx, ta)); assertThat(validationRun).isPresent(); List<ValidationCheck> validationChecks = validationRun.get().getValidationChecks(); assertThat(validationChecks).hasSize(1); assertThat(validationChecks.get(0).getKey()).isEqualTo("trust.anchor.subject.key.matches.locator"); }