Skip to content

Commit

Permalink
Merge branch '1750-preferredkeysever-signature-subpacket' into 'main'
Browse files Browse the repository at this point in the history
#1750 Implement PreferredKeyServer signature subpacket

See merge request root/bc-java!24
  • Loading branch information
dghgit committed Sep 11, 2024
2 parents 0503e2a + c64e774 commit 4a0359c
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.bouncycastle.bcpg.sig.PolicyURI;
import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites;
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
import org.bouncycastle.bcpg.sig.PreferredKeyServer;
import org.bouncycastle.bcpg.sig.PrimaryUserID;
import org.bouncycastle.bcpg.sig.RegularExpression;
import org.bouncycastle.bcpg.sig.Revocable;
Expand Down Expand Up @@ -152,6 +153,8 @@ else if (flags[StreamUtil.flag_partial])
return new PreferredAlgorithms(type, isCritical, isLongLength, data);
case PREFERRED_AEAD_ALGORITHMS:
return new PreferredAEADCiphersuites(isCritical, isLongLength, data);
case PREFERRED_KEY_SERV:
return new PreferredKeyServer(isCritical, isLongLength, data);
case KEY_FLAGS:
return new KeyFlags(isCritical, isLongLength, data);
case POLICY_URL:
Expand Down
46 changes: 46 additions & 0 deletions pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredKeyServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.bouncycastle.bcpg.sig;

import org.bouncycastle.bcpg.SignatureSubpacket;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;

/**
* Signature Subpacket containing the URI of the users preferred key server.
* This is a URI of a key server that the key holder prefers be used for updates.
* Note that keys with multiple User IDs can have a preferred key server for each User ID.
* Note also that since this is a URI, the key server can actually be a copy of the key
* retrieved by ftp, http, finger, etc.
*
* @see <a href="https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.18">
* RFC4880 - Preferred Key Server</a>
* @see <a href="https://www.rfc-editor.org/rfc/rfc9580.html#name-preferred-key-server">
* RFC9580 - Preferred Key Server</a>
*/
public class PreferredKeyServer
extends SignatureSubpacket
{
public PreferredKeyServer(boolean critical, boolean isLongLength, byte[] data)
{
super(SignatureSubpacketTags.PREFERRED_KEY_SERV, critical, isLongLength, data);
}

public PreferredKeyServer(boolean critical, String uri)
{
this(critical, false, Strings.toUTF8ByteArray(uri));
}

/**
* Return the URI of the users preferred key server.
* @return key server uri
*/
public String getURI()
{
return Strings.fromUTF8ByteArray(data);
}

public byte[] getRawURI()
{
return Arrays.clone(data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.bouncycastle.bcpg.sig.NotationData;
import org.bouncycastle.bcpg.sig.PolicyURI;
import org.bouncycastle.bcpg.sig.PreferredAlgorithms;
import org.bouncycastle.bcpg.sig.PreferredKeyServer;
import org.bouncycastle.bcpg.sig.PrimaryUserID;
import org.bouncycastle.bcpg.sig.RegularExpression;
import org.bouncycastle.bcpg.sig.Revocable;
Expand Down Expand Up @@ -202,6 +203,18 @@ public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms)
algorithms));
}

/**
* Specify the preferred key server for the signed user-id / key.
* Note, that the key server might also be a http/ftp etc. URI pointing to the key itself.
*
* @param isCritical true if the subpacket should be treated as critical
* @param uri key server URI
*/
public void setPreferredKeyServer(boolean isCritical, String uri)
{
packets.add(new PreferredKeyServer(isCritical, uri));
}

public void addPolicyURI(boolean isCritical, String policyUri)
{
packets.add(new PolicyURI(isCritical, policyUri));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.sig.Features;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.bcpg.sig.PreferredKeyServer;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
Expand Down Expand Up @@ -458,6 +460,7 @@ public void operation()

PGPSignatureSubpacketGenerator hashed = new PGPSignatureSubpacketGenerator();
hashed.addNotationData(false, true, "test@bouncycastle.org", "hashedNotation");
hashed.setPreferredKeyServer(false, "www.testuri.com");
PGPSignatureSubpacketGenerator unhashed = new PGPSignatureSubpacketGenerator();

PGPContentSignerBuilder signerBuilder = new BcPGPContentSignerBuilder(PublicKeyAlgorithmTags.ECDSA, HashAlgorithmTags.SHA512);
Expand All @@ -472,6 +475,10 @@ public void operation()
PGPSignature signature = (PGPSignature)signatures.next();
isTrue(!signatures.hasNext());

PreferredKeyServer pks = (PreferredKeyServer)signature.getHashedSubPackets().getSubpackets(SignatureSubpacketTags.PREFERRED_KEY_SERV)[0];
isTrue(pks.getURI().equals("www.testuri.com"));
isTrue(pks.getRawURI().length == 15);

verifier = new PGPSignatureVerifierBuilder(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), publicKey).buildDirectKeyVerifier(signature, publicKey);
isTrue(verifier.isVerified());
isTrue(verifier.getSignatureType() == PGPSignature.DIRECT_KEY);
Expand Down

0 comments on commit 4a0359c

Please sign in to comment.