mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-12-10 06:11:08 +01:00
Merge branch 'certification'
This commit is contained in:
commit
b8f4cc3935
11 changed files with 811 additions and 9 deletions
|
|
@ -16,6 +16,7 @@ import org.pgpainless.decryption_verification.DecryptionBuilder;
|
|||
import org.pgpainless.decryption_verification.DecryptionStream;
|
||||
import org.pgpainless.encryption_signing.EncryptionBuilder;
|
||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||
import org.pgpainless.key.certification.CertifyCertificate;
|
||||
import org.pgpainless.key.generation.KeyRingBuilder;
|
||||
import org.pgpainless.key.generation.KeyRingTemplates;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
|
|
@ -163,4 +164,13 @@ public final class PGPainless {
|
|||
public static Policy getPolicy() {
|
||||
return Policy.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create different kinds of signatures on other keys.
|
||||
*
|
||||
* @return builder
|
||||
*/
|
||||
public static CertifyCertificate certify() {
|
||||
return new CertifyCertificate();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Subset of {@link SignatureType}, reduced to certification types.
|
||||
*/
|
||||
public enum CertificationType {
|
||||
|
||||
/**
|
||||
* The issuer of this certification does not make any particular assertion as to how well the certifier has
|
||||
* checked that the owner of the key is in fact the person described by the User ID.
|
||||
*/
|
||||
GENERIC(SignatureType.GENERIC_CERTIFICATION),
|
||||
|
||||
/**
|
||||
* The issuer of this certification has not done any verification of the claim that the owner of this key is
|
||||
* the User ID specified.
|
||||
*/
|
||||
NONE(SignatureType.NO_CERTIFICATION),
|
||||
|
||||
/**
|
||||
* The issuer of this certification has done some casual verification of the claim of identity.
|
||||
*/
|
||||
CASUAL(SignatureType.CASUAL_CERTIFICATION),
|
||||
|
||||
/**
|
||||
* The issuer of this certification has done some casual verification of the claim of identity.
|
||||
*/
|
||||
POSITIVE(SignatureType.POSITIVE_CERTIFICATION),
|
||||
;
|
||||
|
||||
private final SignatureType signatureType;
|
||||
|
||||
CertificationType(@Nonnull SignatureType signatureType) {
|
||||
this.signatureType = signatureType;
|
||||
}
|
||||
|
||||
public @Nonnull SignatureType asSignatureType() {
|
||||
return signatureType;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.algorithm;
|
||||
|
||||
/**
|
||||
* Facade class for {@link org.bouncycastle.bcpg.sig.TrustSignature}.
|
||||
* A trust signature subpacket marks the trustworthiness of a certificate and defines its capabilities to act
|
||||
* as a trusted introducer.
|
||||
*/
|
||||
public class Trustworthiness {
|
||||
|
||||
private final int amount;
|
||||
private final int depth;
|
||||
|
||||
public static final int THRESHOLD_FULLY_CONVINCED = 120; // greater or equal is fully trusted
|
||||
public static final int MARGINALLY_CONVINCED = 60; // default value for marginally convinced
|
||||
public static final int NOT_TRUSTED = 0; // 0 is not trusted
|
||||
|
||||
public Trustworthiness(int amount, int depth) {
|
||||
this.amount = capAmount(amount);
|
||||
this.depth = capDepth(depth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the trust amount.
|
||||
* This value means how confident the issuer of the signature is in validity of the binding.
|
||||
*
|
||||
* @return trust amount
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the depth of the trust signature.
|
||||
* This value controls, whether the certificate can act as a trusted introducer.
|
||||
*
|
||||
* @return depth
|
||||
*/
|
||||
public int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if the trust amount is equal to 0.
|
||||
* This means the key is not trusted.
|
||||
*
|
||||
* Otherwise return false
|
||||
* @return true if untrusted
|
||||
*/
|
||||
public boolean isNotTrusted() {
|
||||
return getAmount() == NOT_TRUSTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the certificate is at least marginally trusted.
|
||||
* That is the case, if the trust amount is greater than 0.
|
||||
*
|
||||
* @return true if the cert is at least marginally trusted
|
||||
*/
|
||||
public boolean isMarginallyTrusted() {
|
||||
return getAmount() > NOT_TRUSTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the certificate is fully trusted. That is the case if the trust amount is
|
||||
* greater than or equal to 120.
|
||||
*
|
||||
* @return true if the cert is fully trusted
|
||||
*/
|
||||
public boolean isFullyTrusted() {
|
||||
return getAmount() >= THRESHOLD_FULLY_CONVINCED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the cert is an introducer. That is the case if the depth is greater 0.
|
||||
*
|
||||
* @return true if introducer
|
||||
*/
|
||||
public boolean isIntroducer() {
|
||||
return getDepth() >= 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the certified cert can introduce certificates with trust depth of <pre>otherDepth</pre>.
|
||||
*
|
||||
* @param otherDepth other certifications trust depth
|
||||
* @return true if the cert can introduce the other
|
||||
*/
|
||||
public boolean canIntroduce(int otherDepth) {
|
||||
return getDepth() > otherDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true, if the certified cert can introduce certificates with the given <pre>other</pre> trust depth.
|
||||
*
|
||||
* @param other other certificates trust depth
|
||||
* @return true if the cert can introduce the other
|
||||
*/
|
||||
public boolean canIntroduce(Trustworthiness other) {
|
||||
return canIntroduce(other.getDepth());
|
||||
}
|
||||
|
||||
/**
|
||||
* This means that we are fully convinced of the trustworthiness of the key.
|
||||
*
|
||||
* @return builder
|
||||
*/
|
||||
public static Builder fullyTrusted() {
|
||||
return new Builder(THRESHOLD_FULLY_CONVINCED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This means that we are marginally (partially) convinced of the trustworthiness of the key.
|
||||
*
|
||||
* @return builder
|
||||
*/
|
||||
public static Builder marginallyTrusted() {
|
||||
return new Builder(MARGINALLY_CONVINCED);
|
||||
}
|
||||
|
||||
/**
|
||||
* This means that we do not trust the key.
|
||||
* Can be used to overwrite previous trust.
|
||||
*
|
||||
* @return builder
|
||||
*/
|
||||
public static Builder untrusted() {
|
||||
return new Builder(NOT_TRUSTED);
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
|
||||
private final int amount;
|
||||
|
||||
private Builder(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key is a trusted introducer (depth 1).
|
||||
* Certifications made by this key are considered trustworthy.
|
||||
*
|
||||
* @return trust
|
||||
*/
|
||||
public Trustworthiness introducer() {
|
||||
return new Trustworthiness(amount, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key is a meta introducer (depth 2).
|
||||
* This key can introduce trusted introducers of depth 1.
|
||||
*
|
||||
* @return trust
|
||||
*/
|
||||
public Trustworthiness metaIntroducer() {
|
||||
return new Trustworthiness(amount, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* The key is a meta introducer of depth <pre>n</pre>.
|
||||
* This key can introduce meta introducers of depth <pre>n - 1</pre>.
|
||||
*
|
||||
* @param n depth
|
||||
* @return trust
|
||||
*/
|
||||
public Trustworthiness metaIntroducerOfDepth(int n) {
|
||||
return new Trustworthiness(amount, n);
|
||||
}
|
||||
}
|
||||
|
||||
private static int capAmount(int amount) {
|
||||
if (amount < 0 || amount > 255) {
|
||||
throw new IllegalArgumentException("Trust amount MUST be a value between 0 and 255");
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
private static int capDepth(int depth) {
|
||||
if (depth < 0 || depth > 255) {
|
||||
throw new IllegalArgumentException("Trust depth MUST be a value between 0 and 255");
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.key.certification;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.CertificationType;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
import org.pgpainless.algorithm.Trustworthiness;
|
||||
import org.pgpainless.exception.KeyException;
|
||||
import org.pgpainless.key.OpenPgpFingerprint;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
import org.pgpainless.signature.builder.ThirdPartyDirectKeySignatureBuilder;
|
||||
import org.pgpainless.signature.builder.ThirdPartyCertificationSignatureBuilder;
|
||||
import org.pgpainless.signature.subpackets.CertificationSubpackets;
|
||||
import org.pgpainless.util.DateUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* API for creating certifications and delegations (Signatures) on keys.
|
||||
* This API can be used to sign another persons OpenPGP key.
|
||||
*
|
||||
* A certification over a user-id is thereby used to attest, that the user believes that the user-id really belongs
|
||||
* to the owner of the certificate.
|
||||
* A delegation over a key can be used to delegate trust by marking the certificate as a trusted introducer.
|
||||
*/
|
||||
public class CertifyCertificate {
|
||||
|
||||
/**
|
||||
* Create a certification over a User-Id.
|
||||
* By default, this method will use {@link CertificationType#GENERIC} to create the signature.
|
||||
* If you need to create another type of certification, use
|
||||
* {@link #userIdOnCertificate(String, PGPPublicKeyRing, CertificationType)} instead.
|
||||
*
|
||||
* @param userId user-id to certify
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
public CertificationOnUserId userIdOnCertificate(@Nonnull String userId,
|
||||
@Nonnull PGPPublicKeyRing certificate) {
|
||||
return new CertificationOnUserId(userId, certificate, CertificationType.GENERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a certification of the given {@link CertificationType} over a User-Id.
|
||||
*
|
||||
* @param userid user-id to certify
|
||||
* @param certificate certificate
|
||||
* @param certificationType type of signature
|
||||
* @return API
|
||||
*/
|
||||
public CertificationOnUserId userIdOnCertificate(@Nonnull String userid,
|
||||
@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull CertificationType certificationType) {
|
||||
return new CertificationOnUserId(userid, certificate, certificationType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer
|
||||
* (see {@link #certificate(PGPPublicKeyRing, Trustworthiness)}).
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @return API
|
||||
*/
|
||||
public DelegationOnCertificate certificate(@Nonnull PGPPublicKeyRing certificate) {
|
||||
return certificate(certificate, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delegation (direct key signature) containing a {@link org.bouncycastle.bcpg.sig.TrustSignature} packet
|
||||
* over a certificate.
|
||||
* This can be used to mark a certificate as a trusted introducer.
|
||||
*
|
||||
* @param certificate certificate
|
||||
* @param trustworthiness trustworthiness of the certificate
|
||||
* @return API
|
||||
*/
|
||||
public DelegationOnCertificate certificate(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nullable Trustworthiness trustworthiness) {
|
||||
return new DelegationOnCertificate(certificate, trustworthiness);
|
||||
}
|
||||
|
||||
public static class CertificationOnUserId {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final String userId;
|
||||
private final CertificationType certificationType;
|
||||
|
||||
CertificationOnUserId(@Nonnull String userId,
|
||||
@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull CertificationType certificationType) {
|
||||
this.userId = userId;
|
||||
this.certificate = certificate;
|
||||
this.certificationType = certificationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the certification using the given key.
|
||||
*
|
||||
* @param certificationKey key used to create the certification
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationOnUserIdWithSubpackets withKey(@Nonnull PGPSecretKeyRing certificationKey,
|
||||
@Nonnull SecretKeyRingProtector protector)
|
||||
throws PGPException {
|
||||
PGPSecretKey secretKey = getCertifyingSecretKey(certificationKey);
|
||||
|
||||
ThirdPartyCertificationSignatureBuilder sigBuilder = new ThirdPartyCertificationSignatureBuilder(
|
||||
certificationType.asSignatureType(), secretKey, protector);
|
||||
|
||||
return new CertificationOnUserIdWithSubpackets(certificate, userId, sigBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CertificationOnUserIdWithSubpackets {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final String userId;
|
||||
private final ThirdPartyCertificationSignatureBuilder sigBuilder;
|
||||
|
||||
CertificationOnUserIdWithSubpackets(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull String userId,
|
||||
@Nonnull ThirdPartyCertificationSignatureBuilder sigBuilder) {
|
||||
this.certificate = certificate;
|
||||
this.userId = userId;
|
||||
this.sigBuilder = sigBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the certification.
|
||||
*
|
||||
* @param subpacketCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult buildWithSubpackets(@Nonnull CertificationSubpackets.Callback subpacketCallback)
|
||||
throws PGPException {
|
||||
sigBuilder.applyCallback(subpacketCallback);
|
||||
return build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the certification signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult build() throws PGPException {
|
||||
PGPSignature signature = sigBuilder.build(certificate, userId);
|
||||
PGPPublicKeyRing certifiedCertificate = KeyRingUtils.injectCertification(certificate, userId, signature);
|
||||
return new CertificationResult(certifiedCertificate, signature);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DelegationOnCertificate {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final Trustworthiness trustworthiness;
|
||||
|
||||
DelegationOnCertificate(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nullable Trustworthiness trustworthiness) {
|
||||
this.certificate = certificate;
|
||||
this.trustworthiness = trustworthiness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the delegation using the given certification key.
|
||||
*
|
||||
* @param certificationKey key to create the certification with
|
||||
* @param protector protector to unlock the certification key
|
||||
* @return API
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public DelegationOnCertificateWithSubpackets withKey(@Nonnull PGPSecretKeyRing certificationKey,
|
||||
@Nonnull SecretKeyRingProtector protector)
|
||||
throws PGPException {
|
||||
PGPSecretKey secretKey = getCertifyingSecretKey(certificationKey);
|
||||
|
||||
ThirdPartyDirectKeySignatureBuilder sigBuilder = new ThirdPartyDirectKeySignatureBuilder(secretKey, protector);
|
||||
if (trustworthiness != null) {
|
||||
sigBuilder.getHashedSubpackets().setTrust(true, trustworthiness.getDepth(), trustworthiness.getAmount());
|
||||
}
|
||||
return new DelegationOnCertificateWithSubpackets(certificate, sigBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DelegationOnCertificateWithSubpackets {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final ThirdPartyDirectKeySignatureBuilder sigBuilder;
|
||||
|
||||
DelegationOnCertificateWithSubpackets(@Nonnull PGPPublicKeyRing certificate,
|
||||
@Nonnull ThirdPartyDirectKeySignatureBuilder sigBuilder) {
|
||||
this.certificate = certificate;
|
||||
this.sigBuilder = sigBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given signature subpackets and build the delegation signature.
|
||||
*
|
||||
* @param subpacketsCallback callback to modify the signatures subpackets
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult buildWithSubpackets(@Nonnull CertificationSubpackets.Callback subpacketsCallback)
|
||||
throws PGPException {
|
||||
sigBuilder.applyCallback(subpacketsCallback);
|
||||
return build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the delegation signature.
|
||||
*
|
||||
* @return result
|
||||
* @throws PGPException in case of an OpenPGP related error
|
||||
*/
|
||||
public CertificationResult build() throws PGPException {
|
||||
PGPPublicKey delegatedKey = certificate.getPublicKey();
|
||||
PGPSignature delegation = sigBuilder.build(delegatedKey);
|
||||
PGPPublicKeyRing delegatedCertificate = KeyRingUtils.injectCertification(certificate, delegatedKey, delegation);
|
||||
return new CertificationResult(delegatedCertificate, delegation);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CertificationResult {
|
||||
|
||||
private final PGPPublicKeyRing certificate;
|
||||
private final PGPSignature certification;
|
||||
|
||||
CertificationResult(@Nonnull PGPPublicKeyRing certificate, @Nonnull PGPSignature certification) {
|
||||
this.certificate = certificate;
|
||||
this.certification = certification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the signature.
|
||||
*
|
||||
* @return signature
|
||||
*/
|
||||
@Nonnull
|
||||
public PGPSignature getCertification() {
|
||||
return certification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the certificate, which now contains the signature.
|
||||
*
|
||||
* @return certificate + signature
|
||||
*/
|
||||
@Nonnull
|
||||
public PGPPublicKeyRing getCertifiedCertificate() {
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
|
||||
private static PGPSecretKey getCertifyingSecretKey(PGPSecretKeyRing certificationKey) {
|
||||
Date now = DateUtil.now();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(certificationKey, now);
|
||||
|
||||
// We only support certification-capable primary keys
|
||||
OpenPgpFingerprint fingerprint = info.getFingerprint();
|
||||
PGPPublicKey certificationPubKey = info.getPublicKey(fingerprint);
|
||||
if (!info.isKeyValidlyBound(certificationPubKey.getKeyID())) {
|
||||
throw new KeyException.RevokedKeyException(fingerprint);
|
||||
}
|
||||
|
||||
Date expirationDate = info.getExpirationDateForUse(KeyFlag.CERTIFY_OTHER);
|
||||
if (expirationDate != null && expirationDate.before(now)) {
|
||||
throw new KeyException.ExpiredKeyException(fingerprint, expirationDate);
|
||||
}
|
||||
|
||||
PGPSecretKey secretKey = certificationKey.getSecretKey(certificationPubKey.getKeyID());
|
||||
if (secretKey == null) {
|
||||
throw new KeyException.MissingSecretKeyException(fingerprint, certificationPubKey.getKeyID());
|
||||
}
|
||||
return secretKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
/**
|
||||
* API for key certifications.
|
||||
*/
|
||||
package org.pgpainless.key.certification;
|
||||
|
|
@ -56,7 +56,7 @@ import org.pgpainless.key.protection.fixes.S2KUsageFix;
|
|||
import org.pgpainless.key.protection.passphrase_provider.SolitaryPassphraseProvider;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
import org.pgpainless.signature.builder.DirectKeySignatureBuilder;
|
||||
import org.pgpainless.signature.builder.DirectKeySelfSignatureBuilder;
|
||||
import org.pgpainless.signature.builder.RevocationSignatureBuilder;
|
||||
import org.pgpainless.signature.builder.SelfSignatureBuilder;
|
||||
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
|
||||
|
|
@ -612,7 +612,7 @@ public class SecretKeyRingEditor implements SecretKeyRingEditorInterface {
|
|||
PGPPublicKey publicKey = primaryKey.getPublicKey();
|
||||
final Date keyCreationTime = publicKey.getCreationTime();
|
||||
|
||||
DirectKeySignatureBuilder builder = new DirectKeySignatureBuilder(primaryKey, secretKeyRingProtector, prevDirectKeySig);
|
||||
DirectKeySelfSignatureBuilder builder = new DirectKeySelfSignatureBuilder(primaryKey, secretKeyRingProtector, prevDirectKeySig);
|
||||
builder.applyCallback(new SelfSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
|
||||
|
|
|
|||
|
|
@ -10,18 +10,19 @@ import org.bouncycastle.openpgp.PGPException;
|
|||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets;
|
||||
|
||||
public class DirectKeySignatureBuilder extends AbstractSignatureBuilder<DirectKeySignatureBuilder> {
|
||||
public class DirectKeySelfSignatureBuilder extends AbstractSignatureBuilder<DirectKeySelfSignatureBuilder> {
|
||||
|
||||
public DirectKeySignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
|
||||
public DirectKeySelfSignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
|
||||
throws PGPException {
|
||||
super(certificationKey, protector, archetypeSignature);
|
||||
}
|
||||
|
||||
public DirectKeySignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
|
||||
public DirectKeySelfSignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
|
||||
super(SignatureType.DIRECT_KEY, signingKey, protector);
|
||||
}
|
||||
|
||||
|
|
@ -41,8 +42,12 @@ public class DirectKeySignatureBuilder extends AbstractSignatureBuilder<DirectKe
|
|||
}
|
||||
|
||||
public PGPSignature build(PGPPublicKey key) throws PGPException {
|
||||
return buildAndInitSignatureGenerator()
|
||||
.generateCertification(key);
|
||||
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
|
||||
if (key.getKeyID() != publicSigningKey.getKeyID()) {
|
||||
return signatureGenerator.generateCertification(publicSigningKey, key);
|
||||
} else {
|
||||
return signatureGenerator.generateCertification(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.signature.builder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
||||
import org.pgpainless.algorithm.SignatureType;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.signature.subpackets.CertificationSubpackets;
|
||||
|
||||
public class ThirdPartyDirectKeySignatureBuilder extends AbstractSignatureBuilder<ThirdPartyDirectKeySignatureBuilder> {
|
||||
|
||||
public ThirdPartyDirectKeySignatureBuilder(PGPSecretKey certificationKey, SecretKeyRingProtector protector, PGPSignature archetypeSignature)
|
||||
throws PGPException {
|
||||
super(certificationKey, protector, archetypeSignature);
|
||||
}
|
||||
|
||||
public ThirdPartyDirectKeySignatureBuilder(PGPSecretKey signingKey, SecretKeyRingProtector protector) throws PGPException {
|
||||
super(SignatureType.DIRECT_KEY, signingKey, protector);
|
||||
}
|
||||
|
||||
public CertificationSubpackets getHashedSubpackets() {
|
||||
return hashedSubpackets;
|
||||
}
|
||||
|
||||
public CertificationSubpackets getUnhashedSubpackets() {
|
||||
return unhashedSubpackets;
|
||||
}
|
||||
|
||||
public void applyCallback(@Nullable CertificationSubpackets.Callback callback) {
|
||||
if (callback != null) {
|
||||
callback.modifyHashedSubpackets(getHashedSubpackets());
|
||||
callback.modifyUnhashedSubpackets(getUnhashedSubpackets());
|
||||
}
|
||||
}
|
||||
|
||||
public PGPSignature build(PGPPublicKey key) throws PGPException {
|
||||
PGPSignatureGenerator signatureGenerator = buildAndInitSignatureGenerator();
|
||||
if (key.getKeyID() != publicSigningKey.getKeyID()) {
|
||||
return signatureGenerator.generateCertification(publicSigningKey, key);
|
||||
} else {
|
||||
return signatureGenerator.generateCertification(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidSignatureType(SignatureType type) {
|
||||
return type == SignatureType.DIRECT_KEY;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue