mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-23 11:27:57 +01:00
Add SignatureValidationUtil and NotationRegistry classes
This commit is contained in:
parent
108d6cb841
commit
217609679d
2 changed files with 155 additions and 0 deletions
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.decryption_verification;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.bcpg.sig.NotationData;
|
||||
import org.bouncycastle.openpgp.PGPDataValidationException;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.pgpainless.algorithm.SignatureSubpacket;
|
||||
import org.pgpainless.util.NotationRegistry;
|
||||
|
||||
/**
|
||||
* Utility class that implements validation of signatures.
|
||||
*/
|
||||
public class SignatureValidationUtil {
|
||||
|
||||
public static void validate(PGPSignature signature) throws PGPException {
|
||||
validateHashedAreaHasSignatureCreationTime(signature);
|
||||
validateSignatureCreationTimeIsNotInUnhashedArea(signature);
|
||||
validateSignatureDoesNotContainCriticalUnknownSubpackets(signature);
|
||||
validateSignatureDoesNotContainCriticalUnknownNotations(signature);
|
||||
}
|
||||
|
||||
public static void validateHashedAreaHasSignatureCreationTime(PGPSignature signature) throws PGPDataValidationException {
|
||||
PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets();
|
||||
if (hashedSubpackets.getSignatureCreationTime() == null) {
|
||||
throw new PGPDataValidationException("Hashed area of the signature MUST carry signature creation time subpacket.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateSignatureCreationTimeIsNotInUnhashedArea(PGPSignature signature) throws PGPDataValidationException {
|
||||
PGPSignatureSubpacketVector unhashedSubpackets = signature.getUnhashedSubPackets();
|
||||
Date unhashedCreationTime = unhashedSubpackets.getSignatureCreationTime();
|
||||
if (unhashedCreationTime == null) {
|
||||
return;
|
||||
}
|
||||
throw new PGPDataValidationException("Signature creation time MUST be in hashed area of the signature.");
|
||||
}
|
||||
|
||||
public static void validateSignatureDoesNotContainCriticalUnknownSubpackets(PGPSignature signature) throws PGPDataValidationException {
|
||||
try {
|
||||
throwIfContainsCriticalUnknownSubpacket(signature.getHashedSubPackets());
|
||||
} catch (PGPDataValidationException e) {
|
||||
throw new PGPDataValidationException("Signature has unknown critical subpacket in hashed area.\n" + e.getMessage());
|
||||
}
|
||||
try {
|
||||
throwIfContainsCriticalUnknownSubpacket(signature.getHashedSubPackets());
|
||||
} catch (PGPDataValidationException e) {
|
||||
throw new PGPDataValidationException("Signature has unknown critical subpacket in unhashed area.\n" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwIfContainsCriticalUnknownSubpacket(PGPSignatureSubpacketVector subpacketVector) throws PGPDataValidationException {
|
||||
for (int critical : subpacketVector.getCriticalTags()) {
|
||||
try {
|
||||
SignatureSubpacket.fromCode(critical);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new PGPDataValidationException("Unknown critical signature subpacket: " + Long.toHexString(critical));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void validateSignatureDoesNotContainCriticalUnknownNotations(PGPSignature signature) throws PGPDataValidationException {
|
||||
PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets();
|
||||
try {
|
||||
throwIfSubpacketsContainCriticalUnknownNotation(hashedSubpackets);
|
||||
} catch (PGPDataValidationException e) {
|
||||
throw new PGPDataValidationException("Signature contains unknown critical notation in hashed area:\n" + e.getMessage());
|
||||
}
|
||||
PGPSignatureSubpacketVector unhashedSubpackets = signature.getUnhashedSubPackets();
|
||||
try {
|
||||
throwIfSubpacketsContainCriticalUnknownNotation(unhashedSubpackets);
|
||||
} catch (PGPDataValidationException e) {
|
||||
throw new PGPDataValidationException("Signature contains unknown critical notation in unhashed area:\n" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwIfSubpacketsContainCriticalUnknownNotation(PGPSignatureSubpacketVector subpacketVector) throws PGPDataValidationException {
|
||||
for (NotationData notation : subpacketVector.getNotationDataOccurrences()) {
|
||||
if (notation.isCritical() && !NotationRegistry.getInstance().isKnownNotation(notation.getNotationName())) {
|
||||
throw new PGPDataValidationException("Critical unknown notation encountered: " + notation.getNotationName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Registry for known notations.
|
||||
* Since signature verification must reject signatures with critical notations that are not known to the application,
|
||||
* there must be some way to tell PGPainless which notations actually are known.
|
||||
*
|
||||
* To add a notation name, call {@link #addKnownNotation(String)}.
|
||||
*/
|
||||
public final class NotationRegistry {
|
||||
|
||||
private static NotationRegistry INSTANCE;
|
||||
private final Set<String> knownNotations = new HashSet<>();
|
||||
|
||||
private NotationRegistry() {
|
||||
|
||||
}
|
||||
|
||||
public static NotationRegistry getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new NotationRegistry();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public void addKnownNotation(String notationName) {
|
||||
if (notationName == null) {
|
||||
throw new NullPointerException("Notation name MUST NOT be null.");
|
||||
}
|
||||
knownNotations.add(notationName);
|
||||
}
|
||||
|
||||
public boolean isKnownNotation(String notationName) {
|
||||
return knownNotations.contains(notationName);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue