diff --git a/core/src/main/java/org/wildfly/channel/Channel.java b/core/src/main/java/org/wildfly/channel/Channel.java index d31f22b6..0f022638 100644 --- a/core/src/main/java/org/wildfly/channel/Channel.java +++ b/core/src/main/java/org/wildfly/channel/Channel.java @@ -231,14 +231,14 @@ public Builder() { public Builder(Channel from) { this.name = from.getName(); - this.repositories = new ArrayList<>(from.getRepositories()); + this.repositories = from.getRepositories() == null ? null : new ArrayList<>(from.getRepositories()); this.manifestCoordinate = from.getManifestCoordinate(); this.blocklistCoordinate = from.getBlocklistCoordinate(); this.strategy = from.getNoStreamStrategy(); this.description = from.getDescription(); this.vendor = from.getVendor(); this.gpgCheck = from._isGpgCheck(); - this.gpgUrls = new ArrayList<>(from.getGpgUrls()); + this.gpgUrls = from.getGpgUrls() == null ? null : new ArrayList<>(from.getGpgUrls()); } public Channel build() { diff --git a/core/src/main/java/org/wildfly/channel/spi/SignatureResult.java b/core/src/main/java/org/wildfly/channel/spi/SignatureResult.java index f02eb8e5..0bbf694e 100644 --- a/core/src/main/java/org/wildfly/channel/spi/SignatureResult.java +++ b/core/src/main/java/org/wildfly/channel/spi/SignatureResult.java @@ -50,8 +50,8 @@ public static SignatureResult noSignature(ArtifactIdentifier resource) { return new SignatureResult(Result.NO_SIGNATURE, resource, null, null); } - public static SignatureResult invalid(ArtifactIdentifier resource) { - return new SignatureResult(Result.INVALID, resource, null, null); + public static SignatureResult invalid(ArtifactIdentifier resource, String keyID) { + return new SignatureResult(Result.INVALID, resource, keyID, null); } public enum Result {OK, NO_MATCHING_CERT, REVOKED, EXPIRED, NO_SIGNATURE, INVALID;} diff --git a/core/src/main/java/org/wildfly/channel/spi/SignatureValidator.java b/core/src/main/java/org/wildfly/channel/spi/SignatureValidator.java index 4a1da13f..daa98dae 100644 --- a/core/src/main/java/org/wildfly/channel/spi/SignatureValidator.java +++ b/core/src/main/java/org/wildfly/channel/spi/SignatureValidator.java @@ -48,19 +48,30 @@ SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStream art */ class SignatureException extends RuntimeException { private final SignatureResult signatureResult; + private String missingSignature; public SignatureException(String message, Throwable cause, SignatureResult signatureResult) { - super(message, cause); + super(buildErrorMessage(message, signatureResult), cause); this.signatureResult = signatureResult; + this.missingSignature = signatureResult.getKeyId(); } public SignatureException(String message, SignatureResult signatureResult) { - super(message); + super(buildErrorMessage(message, signatureResult)); this.signatureResult = signatureResult; + this.missingSignature = signatureResult.getKeyId(); + } + + private static String buildErrorMessage(String message, SignatureResult signatureResult) { + return String.format("%s: %s%s", message, signatureResult.getResult(), signatureResult.getMessage() == null ? "" : signatureResult.getResult()); } public SignatureResult getSignatureResult() { return signatureResult; } + + public String getMissingSignature() { + return missingSignature; + } } } diff --git a/core/src/test/java/org/wildfly/channel/SignedVersionResolverWrapperTest.java b/core/src/test/java/org/wildfly/channel/SignedVersionResolverWrapperTest.java index d781b6c8..e9a9ee91 100644 --- a/core/src/test/java/org/wildfly/channel/SignedVersionResolverWrapperTest.java +++ b/core/src/test/java/org/wildfly/channel/SignedVersionResolverWrapperTest.java @@ -92,7 +92,7 @@ public void invalidSignatureCausesError() throws Exception { when(resolver.resolveArtifact("test.channels", "base-manifest", ChannelManifest.EXTENSION + SIGNATURE_FILE_SUFFIX, ChannelManifest.CLASSIFIER, "1.0.0")) .thenReturn(tempDir.resolve("test-manifest.yaml.asc").toFile()); - when(signatureValidator.validateSignature(any(), any(), any(), any())).thenReturn(SignatureResult.invalid(mock(ArtifactIdentifier.class))); + when(signatureValidator.validateSignature(any(), any(), any(), any())).thenReturn(SignatureResult.invalid(mock(ArtifactIdentifier.class), "abcd")); assertThrows(SignatureValidator.SignatureException.class, () -> signedResolver.resolveChannelMetadata(List.of(new ChannelManifestCoordinate("test.channels", "base-manifest", "1.0.0")))); } @@ -154,7 +154,7 @@ public void failedSignatureValidationThrowsException() throws Exception { ARTIFACT.classifier, ARTIFACT.version)) .thenReturn(signatureFile); when(signatureValidator.validateSignature(eq(ARTIFACT), - any(), any(), any())).thenReturn(SignatureResult.invalid(ARTIFACT)); + any(), any(), any())).thenReturn(SignatureResult.invalid(ARTIFACT, "abcd")); assertThrows(SignatureValidator.SignatureException.class, () -> signedResolver.resolveArtifact(ARTIFACT.groupId, ARTIFACT.artifactId, ARTIFACT.extension, ARTIFACT.classifier, ARTIFACT.version)); diff --git a/gpg-validator/pom.xml b/gpg-validator/pom.xml index 39ab2bc3..0dac107d 100644 --- a/gpg-validator/pom.xml +++ b/gpg-validator/pom.xml @@ -3,7 +3,7 @@ channel-parent org.wildfly.channel - 1.2.1.Final-SNAPSHOT + 1.2.2.Final-SNAPSHOT 4.0.0 diff --git a/gpg-validator/src/main/java/org/wildfly/channel/gpg/GpgSignatureValidator.java b/gpg-validator/src/main/java/org/wildfly/channel/gpg/GpgSignatureValidator.java index 889c7dfa..84d38174 100644 --- a/gpg-validator/src/main/java/org/wildfly/channel/gpg/GpgSignatureValidator.java +++ b/gpg-validator/src/main/java/org/wildfly/channel/gpg/GpgSignatureValidator.java @@ -105,7 +105,7 @@ public SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStr return SignatureResult.noSignature(artifactId); } - final String keyID = Long.toHexString(pgpSignature.getKeyID()).toUpperCase(Locale.ROOT); + final String keyID = getKeyID(pgpSignature); if (LOG.isTraceEnabled()) { LOG.tracef("The signature was created using public key %s.", keyID); } @@ -134,7 +134,7 @@ public SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStr } } catch (PGPException | IOException e) { throw new SignatureException("Unable to parse the certificate downloaded from keyserver", e, - SignatureResult.noSignature(artifactId)); + SignatureResult.noMatchingCertificate(artifactId, keyID)); } if (key == null) { @@ -146,7 +146,7 @@ public SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStr pgpPublicKeys = downloadPublicKey(gpgUrl); } catch (IOException e) { throw new SignatureException("Unable to parse the certificate downloaded from " + gpgUrl, e, - SignatureResult.noSignature(artifactId)); + SignatureResult.noMatchingCertificate(artifactId, keyID)); } if (pgpPublicKeys.stream().anyMatch(k -> k.getKeyID() == pgpSignature.getKeyID())) { key = pgpPublicKeys.stream().filter(k -> k.getKeyID() == pgpSignature.getKeyID()).findFirst().get(); @@ -193,7 +193,7 @@ public SignatureResult validateSignature(ArtifactIdentifier artifactId, InputStr pgpSignature.init(new BcPGPContentVerifierBuilderProvider(), publicKey); } catch (PGPException e) { throw new SignatureException("Unable to verify the signature using key " + keyID, e, - SignatureResult.invalid(artifactId)); + SignatureResult.invalid(artifactId, keyID)); } final SignatureResult result = verifyFile(artifactId, artifactStream, pgpSignature); @@ -241,7 +241,7 @@ private SignatureResult checkRevoked(ArtifactIdentifier artifactId, String keyID final Iterator subKeys = publicKey.getSignaturesOfType(PGPSignature.SUBKEY_BINDING); while (subKeys.hasNext()) { final PGPSignature subKeySignature = subKeys.next(); - final PGPPublicKey subKey = keystore.get(Long.toHexString(subKeySignature.getKeyID()).toUpperCase(Locale.ROOT)); + final PGPPublicKey subKey = keystore.get(getKeyID(subKeySignature)); if (subKey.hasRevocation()) { if (LOG.isTraceEnabled()) { LOG.tracef("Sub-key %s has been revoked.", Long.toHexString(subKey.getKeyID()).toUpperCase(Locale.ROOT)); @@ -285,16 +285,20 @@ private static SignatureResult verifyFile(ArtifactIdentifier artifactSource, Inp // Verify the signature try { if (!pgpSignature.verify()) { - return SignatureResult.invalid(artifactSource); + return SignatureResult.invalid(artifactSource, getKeyID(pgpSignature)); } else { return SignatureResult.ok(); } } catch (PGPException e) { throw new SignatureException("Unable to verify the file signature", e, - SignatureResult.invalid(artifactSource)); + SignatureResult.invalid(artifactSource, getKeyID(pgpSignature))); } } + private static String getKeyID(PGPSignature pgpSignature) { + return Long.toHexString(pgpSignature.getKeyID()).toUpperCase(Locale.ROOT); + } + private static PGPSignature readSignatureFile(InputStream signatureStream) throws IOException { PGPSignature pgpSignature = null; try (InputStream decoderStream = PGPUtil.getDecoderStream(signatureStream)) {