1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-10 10:49:39 +02:00

Update SOP implementation to the latest spec version

See https://datatracker.ietf.org/doc/html/draft-dkg-openpgp-stateless-cli-03
This commit is contained in:
Paul Schaub 2022-01-07 14:28:36 +01:00
parent 5e0ca369bf
commit 1cb49f4b12
21 changed files with 348 additions and 112 deletions

View file

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.OutputStream;
import java.io.PrintWriter;
public class MicAlg {
private final String micAlg;
public MicAlg(String micAlg) {
if (micAlg == null) {
throw new IllegalArgumentException("MicAlg String cannot be null.");
}
this.micAlg = micAlg;
}
public static MicAlg empty() {
return new MicAlg("");
}
public static MicAlg fromHashAlgorithmId(int id) {
switch (id) {
case 1:
return new MicAlg("pgp-md5");
case 2:
return new MicAlg("pgp-sha1");
case 3:
return new MicAlg("pgp-ripemd160");
case 8:
return new MicAlg("pgp-sha256");
case 9:
return new MicAlg("pgp-sha384");
case 10:
return new MicAlg("pgp-sha512");
case 11:
return new MicAlg("pgp-sha224");
default:
throw new IllegalArgumentException("Unsupported hash algorithm ID: " + id);
}
}
public String getMicAlg() {
return micAlg;
}
public void writeTo(OutputStream outputStream) {
PrintWriter pw = new PrintWriter(outputStream);
pw.write(getMicAlg());
pw.close();
}
}

View file

@ -24,6 +24,9 @@ public abstract class SOPGPException extends RuntimeException {
public abstract int getExitCode();
/**
* No acceptable signatures found (sop verify).
*/
public static class NoSignature extends SOPGPException {
public static final int EXIT_CODE = 3;
@ -38,6 +41,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Asymmetric algorithm unsupported (sop encrypt).
*/
public static class UnsupportedAsymmetricAlgo extends SOPGPException {
public static final int EXIT_CODE = 13;
@ -56,6 +62,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Certificate not encryption capable (e,g, expired, revoked, unacceptable usage).
*/
public static class CertCannotEncrypt extends SOPGPException {
public static final int EXIT_CODE = 17;
@ -69,10 +78,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
public static class CertCannotSign extends Exception {
}
/**
* Missing required argument.
*/
public static class MissingArg extends SOPGPException {
public static final int EXIT_CODE = 19;
@ -87,6 +95,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Incomplete verification instructions (sop decrypt).
*/
public static class IncompleteVerification extends SOPGPException {
public static final int EXIT_CODE = 23;
@ -101,6 +112,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Unable to decrypt (sop decrypt).
*/
public static class CannotDecrypt extends SOPGPException {
public static final int EXIT_CODE = 29;
@ -111,6 +125,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Non-UTF-8 or otherwise unreliable password (sop encrypt).
*/
public static class PasswordNotHumanReadable extends SOPGPException {
public static final int EXIT_CODE = 31;
@ -121,6 +138,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Unsupported option.
*/
public static class UnsupportedOption extends SOPGPException {
public static final int EXIT_CODE = 37;
@ -139,6 +159,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Invalid data type (no secret key where KEYS expected, etc.).
*/
public static class BadData extends SOPGPException {
public static final int EXIT_CODE = 41;
@ -157,6 +180,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Non-Text input where text expected.
*/
public static class ExpectedText extends SOPGPException {
public static final int EXIT_CODE = 53;
@ -167,6 +193,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Output file already exists.
*/
public static class OutputExists extends SOPGPException {
public static final int EXIT_CODE = 59;
@ -181,6 +210,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Input file does not exist.
*/
public static class MissingInput extends SOPGPException {
public static final int EXIT_CODE = 61;
@ -195,6 +227,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* A KEYS input is protected (locked) with a password, and sop cannot unlock it.
*/
public static class KeyIsProtected extends SOPGPException {
public static final int EXIT_CODE = 67;
@ -213,6 +248,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* Unsupported subcommand.
*/
public static class UnsupportedSubcommand extends SOPGPException {
public static final int EXIT_CODE = 69;
@ -227,6 +265,9 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* An indirect parameter is a special designator (it starts with @), but sop does not know how to handle the prefix.
*/
public static class UnsupportedSpecialPrefix extends SOPGPException {
public static final int EXIT_CODE = 71;
@ -237,7 +278,10 @@ public abstract class SOPGPException extends RuntimeException {
}
}
/**
* A indirect input parameter is a special designator (it starts with @),
* and a filename matching the designator is actually present.
*/
public static class AmbiguousInput extends SOPGPException {
public static final int EXIT_CODE = 73;
@ -251,4 +295,30 @@ public abstract class SOPGPException extends RuntimeException {
return EXIT_CODE;
}
}
/**
* Key not signature-capable (e.g. expired, revoked, unacceptable usage flags)
* (sop sign and sop encrypt with --sign-with).
*/
public static class KeyCannotSign extends SOPGPException {
public static final int EXIT_CODE = 79;
public KeyCannotSign() {
super();
}
public KeyCannotSign(String message) {
super(message);
}
public KeyCannotSign(String s, KeyCannotSign keyCannotSign) {
super(s, keyCannotSign);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
}

View file

@ -35,9 +35,9 @@ public interface Decrypt {
throws SOPGPException.UnsupportedOption;
/**
* Adds the verification cert.
* Adds one or more verification cert.
*
* @param cert input stream containing the cert
* @param cert input stream containing the cert(s)
* @return builder instance
*/
Decrypt verifyWithCert(InputStream cert)
@ -45,9 +45,9 @@ public interface Decrypt {
IOException;
/**
* Adds the verification cert.
* Adds one or more verification cert.
*
* @param cert byte array containing the cert
* @param cert byte array containing the cert(s)
* @return builder instance
*/
default Decrypt verifyWithCert(byte[] cert)
@ -75,9 +75,9 @@ public interface Decrypt {
SOPGPException.UnsupportedOption;
/**
* Adds the decryption key.
* Adds one or more decryption key.
*
* @param key input stream containing the key
* @param key input stream containing the key(s)
* @return builder instance
*/
Decrypt withKey(InputStream key)
@ -86,9 +86,9 @@ public interface Decrypt {
SOPGPException.UnsupportedAsymmetricAlgo;
/**
* Adds the decryption key.
* Adds one or more decryption key.
*
* @param key byte array containing the key
* @param key byte array containing the key(s)
* @return builder instance
*/
default Decrypt withKey(byte[] key)

View file

@ -38,7 +38,7 @@ public interface Encrypt {
*/
Encrypt signWith(InputStream key)
throws SOPGPException.KeyIsProtected,
SOPGPException.CertCannotSign,
SOPGPException.KeyCannotSign,
SOPGPException.UnsupportedAsymmetricAlgo,
SOPGPException.BadData;
@ -50,7 +50,7 @@ public interface Encrypt {
*/
default Encrypt signWith(byte[] key)
throws SOPGPException.KeyIsProtected,
SOPGPException.CertCannotSign,
SOPGPException.KeyCannotSign,
SOPGPException.UnsupportedAsymmetricAlgo,
SOPGPException.BadData {
return signWith(new ByteArrayInputStream(key));

View file

@ -21,18 +21,18 @@ public interface ExtractCert {
ExtractCert noArmor();
/**
* Extract the cert from the provided key.
* Extract the cert(s) from the provided key(s).
*
* @param keyInputStream input stream containing the encoding of an OpenPGP key
* @return result containing the encoding of the keys cert
* @param keyInputStream input stream containing the encoding of one or more OpenPGP keys
* @return result containing the encoding of the keys certs
*/
Ready key(InputStream keyInputStream) throws IOException, SOPGPException.BadData;
/**
* Extract the cert from the provided key.
* Extract the cert(s) from the provided key(s).
*
* @param key byte array containing the encoding of an OpenPGP key
* @return result containing the encoding of the keys cert
* @param key byte array containing the encoding of one or more OpenPGP key
* @return result containing the encoding of the keys certs
*/
default Ready key(byte[] key) throws IOException, SOPGPException.BadData {
return key(new ByteArrayInputStream(key));

View file

@ -8,7 +8,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import sop.Ready;
import sop.MicAlg;
import sop.ReadyWithResult;
import sop.enums.SignAs;
import sop.exception.SOPGPException;
@ -31,17 +32,17 @@ public interface Sign {
Sign mode(SignAs mode) throws SOPGPException.UnsupportedOption;
/**
* Adds the signer key.
* Add one or more signing keys.
*
* @param key input stream containing encoded key
* @param key input stream containing encoded keys
* @return builder instance
*/
Sign key(InputStream key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException;
/**
* Adds the signer key.
* Add one or more signing keys.
*
* @param key byte array containing encoded key
* @param key byte array containing encoded keys
* @return builder instance
*/
default Sign key(byte[] key) throws SOPGPException.KeyIsProtected, SOPGPException.BadData, IOException {
@ -54,7 +55,7 @@ public interface Sign {
* @param data input stream containing data
* @return ready
*/
Ready data(InputStream data) throws IOException, SOPGPException.ExpectedText;
ReadyWithResult<MicAlg> data(InputStream data) throws IOException, SOPGPException.ExpectedText;
/**
* Signs data.
@ -62,7 +63,7 @@ public interface Sign {
* @param data byte array containing data
* @return ready
*/
default Ready data(byte[] data) throws IOException, SOPGPException.ExpectedText {
default ReadyWithResult<MicAlg> data(byte[] data) throws IOException, SOPGPException.ExpectedText {
return data(new ByteArrayInputStream(data));
}
}

View file

@ -29,17 +29,17 @@ public interface Verify extends VerifySignatures {
Verify notAfter(Date timestamp) throws SOPGPException.UnsupportedOption;
/**
* Adds the verification cert.
* Add one or more verification cert.
*
* @param cert input stream containing the encoded cert
* @param cert input stream containing the encoded certs
* @return builder instance
*/
Verify cert(InputStream cert) throws SOPGPException.BadData;
/**
* Adds the verification cert.
* Add one or more verification cert.
*
* @param cert byte array containing the encoded cert
* @param cert byte array containing the encoded certs
* @return builder instance
*/
default Verify cert(byte[] cert) throws SOPGPException.BadData {

View file

@ -8,15 +8,42 @@ public interface Version {
/**
* Return the implementations name.
* e.g. "SOP",
*
* @return implementation name
*/
String getName();
/**
* Return the implementations version string.
* Return the implementations short version string.
* e.g. "1.0"
*
* @return version string
*/
String getVersion();
/**
* Return version information about the used OpenPGP backend.
* e.g. "Bouncycastle 1.70"
*
* @return backend version string
*/
String getBackendVersion();
/**
* Return an extended version string containing multiple lines of version information.
* The first line MUST match the information produced by {@link #getName()} and {@link #getVersion()}, but the rest of the text
* has no defined structure.
* Example:
* <pre>
* "SOP 1.0
* Awesome PGP!
* Using Bouncycastle 1.70
* LibFoo 1.2.2
* See https://pgp.example.org/sop/ for more information"
* </pre>
*
* @return extended version string
*/
String getExtendedVersion();
}