mirror of
https://codeberg.org/PGPainless/sop-java.git
synced 2025-09-09 10:19:47 +02:00
Compare commits
9 commits
1084cf6128
...
ced207382c
Author | SHA1 | Date | |
---|---|---|---|
ced207382c | |||
4325bfb2ee | |||
6796ec95e7 | |||
a705bb4c3d | |||
051499974d | |||
cbdcfe54cb | |||
f7e6de4aaa | |||
a906028ce7 | |||
3700c60fde |
12 changed files with 280 additions and 42 deletions
29
.reuse/dep5
29
.reuse/dep5
|
@ -1,29 +0,0 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: SOP-Java
|
|
||||||
Upstream-Contact: Paul Schaub <info@pgpainless.org>
|
|
||||||
Source: https://pgpainless.org
|
|
||||||
|
|
||||||
# Sample paragraph, commented out:
|
|
||||||
#
|
|
||||||
# Files: src/*
|
|
||||||
# Copyright: $YEAR $NAME <$CONTACT>
|
|
||||||
# License: ...
|
|
||||||
|
|
||||||
# Gradle build tool
|
|
||||||
Files: gradle*
|
|
||||||
Copyright: 2015 the original author or authors.
|
|
||||||
License: Apache-2.0
|
|
||||||
|
|
||||||
# Woodpecker build files
|
|
||||||
Files: .woodpecker/*
|
|
||||||
Copyright: 2022 the original author or authors.
|
|
||||||
License: Apache-2.0
|
|
||||||
|
|
||||||
Files: external-sop/src/main/resources/sop/testsuite/external/*
|
|
||||||
Copyright: 2023 the original author or authors
|
|
||||||
License: Apache-2.0
|
|
||||||
|
|
||||||
# Github Issue Templates
|
|
||||||
Files: .github/ISSUE_TEMPLATE/*
|
|
||||||
Copyright: 2024 the original author or authors
|
|
||||||
License: Apache-2.0
|
|
32
REUSE.toml
Normal file
32
REUSE.toml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-FileCopyrightText: 2025 Paul Schaub <info@pgpainless.org>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
version = 1
|
||||||
|
SPDX-PackageName = "SOP-Java"
|
||||||
|
SPDX-PackageSupplier = "Paul Schaub <info@pgpainless.org>"
|
||||||
|
SPDX-PackageDownloadLocation = "https://pgpainless.org"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "gradle**"
|
||||||
|
precedence = "aggregate"
|
||||||
|
SPDX-FileCopyrightText = "2015 the original author or authors."
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = ".woodpecker/**"
|
||||||
|
precedence = "aggregate"
|
||||||
|
SPDX-FileCopyrightText = "2022 the original author or authors."
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "external-sop/src/main/resources/sop/testsuite/external/**"
|
||||||
|
precedence = "aggregate"
|
||||||
|
SPDX-FileCopyrightText = "2023 the original author or authors"
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = ".github/ISSUE_TEMPLATE/**"
|
||||||
|
precedence = "aggregate"
|
||||||
|
SPDX-FileCopyrightText = "2024 the original author or authors"
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
|
@ -21,7 +21,7 @@ class UpdateKeyExternal(binary: String, environment: Properties) : UpdateKey {
|
||||||
|
|
||||||
override fun signingOnly(): UpdateKey = apply { commandList.add("--signing-only") }
|
override fun signingOnly(): UpdateKey = apply { commandList.add("--signing-only") }
|
||||||
|
|
||||||
override fun noNewMechanisms(): UpdateKey = apply { commandList.add("--no-new-mechanisms") }
|
override fun noAddedCapabilities(): UpdateKey = apply { commandList.add("--no-added-capabilities") }
|
||||||
|
|
||||||
override fun withKeyPassword(password: ByteArray): UpdateKey = apply {
|
override fun withKeyPassword(password: ByteArray): UpdateKey = apply {
|
||||||
commandList.add("--with-key-password=@ENV:KEY_PASSWORD_$argCount")
|
commandList.add("--with-key-password=@ENV:KEY_PASSWORD_$argCount")
|
||||||
|
|
|
@ -88,7 +88,10 @@ class SopCLI {
|
||||||
// Hide generate-completion command
|
// Hide generate-completion command
|
||||||
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
subcommands["generate-completion"]?.commandSpec?.usageMessage()?.hidden(true)
|
||||||
// render Input/Output sections in help command
|
// render Input/Output sections in help command
|
||||||
subcommands.values.filter { (it.getCommand() as Any) is AbstractSopCmd } // Only for AbstractSopCmd objects
|
subcommands.values
|
||||||
|
.filter {
|
||||||
|
(it.getCommand() as Any) is AbstractSopCmd
|
||||||
|
} // Only for AbstractSopCmd objects
|
||||||
.forEach { (it.getCommand() as AbstractSopCmd).installIORenderer(it) }
|
.forEach { (it.getCommand() as AbstractSopCmd).installIORenderer(it) }
|
||||||
// overwrite executable name
|
// overwrite executable name
|
||||||
commandName = EXECUTABLE_NAME
|
commandName = EXECUTABLE_NAME
|
||||||
|
@ -96,7 +99,8 @@ class SopCLI {
|
||||||
executionExceptionHandler = SOPExecutionExceptionHandler()
|
executionExceptionHandler = SOPExecutionExceptionHandler()
|
||||||
exitCodeExceptionMapper = SOPExceptionExitCodeMapper()
|
exitCodeExceptionMapper = SOPExceptionExitCodeMapper()
|
||||||
isCaseInsensitiveEnumValuesAllowed = true
|
isCaseInsensitiveEnumValuesAllowed = true
|
||||||
}.execute(*args)
|
}
|
||||||
|
.execute(*args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import sop.exception.SOPGPException
|
||||||
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
exitCodeOnInvalidInput = SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||||
class MergeCertsCmd : AbstractSopCmd() {
|
class MergeCertsCmd : AbstractSopCmd() {
|
||||||
|
|
||||||
@CommandLine.Option(names = ["--no-armor"], negatable = true) var armor = false
|
@CommandLine.Option(names = ["--no-armor"], negatable = true) var armor = true
|
||||||
|
|
||||||
@CommandLine.Parameters(paramLabel = "CERTS") var updates: List<String> = listOf()
|
@CommandLine.Parameters(paramLabel = "CERTS") var updates: List<String> = listOf()
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ class UpdateKeyCmd : AbstractSopCmd() {
|
||||||
|
|
||||||
@Option(names = ["--signing-only"]) var signingOnly = false
|
@Option(names = ["--signing-only"]) var signingOnly = false
|
||||||
|
|
||||||
@Option(names = ["--no-new-mechanisms"]) var noNewMechanisms = false
|
@Option(names = ["--no-added-capabilities"]) var noAddedCapabilities = false
|
||||||
|
|
||||||
@Option(names = ["--with-key-password"], paramLabel = "PASSWORD")
|
@Option(names = ["--with-key-password"], paramLabel = "PASSWORD")
|
||||||
var withKeyPassword: List<String> = listOf()
|
var withKeyPassword: List<String> = listOf()
|
||||||
|
@ -38,8 +38,8 @@ class UpdateKeyCmd : AbstractSopCmd() {
|
||||||
updateKey.signingOnly()
|
updateKey.signingOnly()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noNewMechanisms) {
|
if (noAddedCapabilities) {
|
||||||
updateKey.noNewMechanisms()
|
updateKey.noAddedCapabilities()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (passwordFileName in withKeyPassword) {
|
for (passwordFileName in withKeyPassword) {
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
package sop.cli.picocli.commands
|
package sop.cli.picocli.commands
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
import picocli.CommandLine.Command
|
import picocli.CommandLine.Command
|
||||||
import picocli.CommandLine.Option
|
import picocli.CommandLine.Option
|
||||||
import picocli.CommandLine.Parameters
|
import picocli.CommandLine.Parameters
|
||||||
import sop.cli.picocli.SopCLI
|
import sop.cli.picocli.SopCLI
|
||||||
import sop.exception.SOPGPException
|
import sop.exception.SOPGPException
|
||||||
import sop.util.HexUtil.Companion.bytesToHex
|
import sop.util.HexUtil.Companion.bytesToHex
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
name = "validate-userid",
|
name = "validate-userid",
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package sop.testsuite.operation;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.condition.EnabledIf;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
import sop.SOP;
|
||||||
|
import sop.exception.SOPGPException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
|
||||||
|
public class CertifyValidateUserIdTest {
|
||||||
|
|
||||||
|
static Stream<Arguments> provideInstances() {
|
||||||
|
return AbstractSOPTest.provideBackends();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideInstances")
|
||||||
|
public void certifyUserId(SOP sop) throws IOException {
|
||||||
|
byte[] aliceKey = sop.generateKey()
|
||||||
|
.withKeyPassword("sw0rdf1sh")
|
||||||
|
.userId("Alice <alice@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] aliceCert = sop.extractCert()
|
||||||
|
.key(aliceKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
byte[] bobKey = sop.generateKey()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] bobCert = sop.extractCert()
|
||||||
|
.key(bobKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
// Alice has her own user-id self-certified
|
||||||
|
assertTrue(sop.validateUserId()
|
||||||
|
.authorities(aliceCert)
|
||||||
|
.userId("Alice <alice@pgpainless.org>")
|
||||||
|
.subjects(aliceCert),
|
||||||
|
"Alice accepts her own self-certified user-id");
|
||||||
|
|
||||||
|
// Alice has not yet certified Bobs user-id
|
||||||
|
assertFalse(sop.validateUserId()
|
||||||
|
.authorities(aliceCert)
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.subjects(bobCert),
|
||||||
|
"Alice has not yet certified Bobs user-id");
|
||||||
|
|
||||||
|
byte[] bobCertifiedByAlice = sop.certifyUserId()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.withKeyPassword("sw0rdf1sh")
|
||||||
|
.keys(aliceKey)
|
||||||
|
.certs(bobCert)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
assertTrue(sop.validateUserId()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.authorities(aliceCert)
|
||||||
|
.subjects(bobCertifiedByAlice),
|
||||||
|
"Alice accepts Bobs user-id after she certified it");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideInstances")
|
||||||
|
public void addPetName(SOP sop) throws IOException {
|
||||||
|
byte[] aliceKey = sop.generateKey()
|
||||||
|
.userId("Alice <alice@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] aliceCert = sop.extractCert()
|
||||||
|
.key(aliceKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
byte[] bobKey = sop.generateKey()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] bobCert = sop.extractCert()
|
||||||
|
.key(bobKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
assertThrows(SOPGPException.CertUserIdNoMatch.class, () ->
|
||||||
|
sop.certifyUserId()
|
||||||
|
.userId("Bobby")
|
||||||
|
.keys(aliceKey)
|
||||||
|
.certs(bobCert)
|
||||||
|
.getBytes(),
|
||||||
|
"Alice cannot create a pet-name for Bob without the --no-require-self-sig flag");
|
||||||
|
|
||||||
|
byte[] bobWithPetName = sop.certifyUserId()
|
||||||
|
.userId("Bobby")
|
||||||
|
.noRequireSelfSig()
|
||||||
|
.keys(aliceKey)
|
||||||
|
.certs(bobCert)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
assertTrue(sop.validateUserId()
|
||||||
|
.userId("Bobby")
|
||||||
|
.authorities(aliceCert)
|
||||||
|
.subjects(bobWithPetName),
|
||||||
|
"Alice accepts the pet-name she gave to Bob");
|
||||||
|
|
||||||
|
assertFalse(sop.validateUserId()
|
||||||
|
.userId("Bobby")
|
||||||
|
.authorities(bobWithPetName)
|
||||||
|
.subjects(bobWithPetName),
|
||||||
|
"Bob does not accept the pet-name Alice gave him");
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("provideInstances")
|
||||||
|
public void certifyWithRevokedKey(SOP sop) throws IOException {
|
||||||
|
byte[] aliceKey = sop.generateKey()
|
||||||
|
.userId("Alice <alice@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] aliceRevokedCert = sop.revokeKey()
|
||||||
|
.keys(aliceKey)
|
||||||
|
.getBytes();
|
||||||
|
byte[] aliceRevokedKey = sop.updateKey()
|
||||||
|
.mergeCerts(aliceRevokedCert)
|
||||||
|
.key(aliceKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
byte[] bobKey = sop.generateKey()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.generate()
|
||||||
|
.getBytes();
|
||||||
|
byte[] bobCert = sop.extractCert()
|
||||||
|
.key(bobKey)
|
||||||
|
.getBytes();
|
||||||
|
|
||||||
|
assertThrows(SOPGPException.KeyCannotCertify.class, () ->
|
||||||
|
sop.certifyUserId()
|
||||||
|
.userId("Bob <bob@pgpainless.org>")
|
||||||
|
.keys(aliceRevokedKey)
|
||||||
|
.certs(bobCert)
|
||||||
|
.getBytes());
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,9 +9,10 @@ package sop
|
||||||
*
|
*
|
||||||
* @param micAlg string identifying the digest mechanism used to create the signed message. This is
|
* @param micAlg string identifying the digest mechanism used to create the signed message. This is
|
||||||
* useful for setting the `micalg=` parameter for the multipart/signed content-type of a PGP/MIME
|
* useful for setting the `micalg=` parameter for the multipart/signed content-type of a PGP/MIME
|
||||||
* object as described in section 5 of [RFC3156](https://www.rfc-editor.org/rfc/rfc3156#section-5).
|
* object as described in section 5 of
|
||||||
* If more than one signature was generated and different digest mechanisms were used, the value
|
* [RFC3156](https://www.rfc-editor.org/rfc/rfc3156#section-5). If more than one signature was
|
||||||
* of the micalg object is an empty string.
|
* generated and different digest mechanisms were used, the value of the micalg object is an empty
|
||||||
|
* string.
|
||||||
*/
|
*/
|
||||||
data class SigningResult(val micAlg: MicAlg) {
|
data class SigningResult(val micAlg: MicAlg) {
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,22 @@ abstract class SOPGPException : RuntimeException {
|
||||||
|
|
||||||
abstract fun getExitCode(): Int
|
abstract fun getExitCode(): Int
|
||||||
|
|
||||||
|
/** An otherwise unspecified failure occurred */
|
||||||
|
class UnspecificFailure : SOPGPException {
|
||||||
|
|
||||||
|
constructor(message: String) : super(message)
|
||||||
|
|
||||||
|
constructor(message: String, e: Throwable) : super(message, e)
|
||||||
|
|
||||||
|
constructor(e: Throwable) : super(e)
|
||||||
|
|
||||||
|
override fun getExitCode(): Int = EXIT_CODE
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXIT_CODE = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** No acceptable signatures found (sop verify, inline-verify). */
|
/** No acceptable signatures found (sop verify, inline-verify). */
|
||||||
class NoSignature : SOPGPException {
|
class NoSignature : SOPGPException {
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
|
@ -378,4 +394,23 @@ abstract class SOPGPException : RuntimeException {
|
||||||
const val EXIT_CODE = 107
|
const val EXIT_CODE = 107
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Key not certification-capable (e.g., expired, revoked, unacceptable usage flags) (sop
|
||||||
|
* certify-userid)
|
||||||
|
*/
|
||||||
|
class KeyCannotCertify : SOPGPException {
|
||||||
|
|
||||||
|
constructor(message: String) : super(message)
|
||||||
|
|
||||||
|
constructor(message: String, e: Throwable) : super(message, e)
|
||||||
|
|
||||||
|
constructor(e: Throwable) : super(e)
|
||||||
|
|
||||||
|
override fun getExitCode(): Int = EXIT_CODE
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val EXIT_CODE = 109
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,25 +19,61 @@ interface UpdateKey {
|
||||||
*/
|
*/
|
||||||
fun noArmor(): UpdateKey
|
fun noArmor(): UpdateKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow key to be used for signing only.
|
||||||
|
* If this option is not present, the operation may add a new, encryption-capable component key.
|
||||||
|
*/
|
||||||
@Throws(SOPGPException.UnsupportedOption::class) fun signingOnly(): UpdateKey
|
@Throws(SOPGPException.UnsupportedOption::class) fun signingOnly(): UpdateKey
|
||||||
|
|
||||||
@Throws(SOPGPException.UnsupportedOption::class) fun noNewMechanisms(): UpdateKey
|
/**
|
||||||
|
* Do not allow adding new capabilities to the key.
|
||||||
|
* If this option is not present, the operation may add support for new capabilities to the key.
|
||||||
|
*/
|
||||||
|
@Throws(SOPGPException.UnsupportedOption::class) fun noAddedCapabilities(): UpdateKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a passphrase for unlocking the secret key.
|
||||||
|
*
|
||||||
|
* @param password password
|
||||||
|
*/
|
||||||
@Throws(SOPGPException.PasswordNotHumanReadable::class, SOPGPException.UnsupportedOption::class)
|
@Throws(SOPGPException.PasswordNotHumanReadable::class, SOPGPException.UnsupportedOption::class)
|
||||||
fun withKeyPassword(password: String): UpdateKey =
|
fun withKeyPassword(password: String): UpdateKey =
|
||||||
withKeyPassword(password.toByteArray(UTF8Util.UTF8))
|
withKeyPassword(password.toByteArray(UTF8Util.UTF8))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a passphrase for unlocking the secret key.
|
||||||
|
*
|
||||||
|
* @param password password
|
||||||
|
*/
|
||||||
@Throws(SOPGPException.PasswordNotHumanReadable::class, SOPGPException.UnsupportedOption::class)
|
@Throws(SOPGPException.PasswordNotHumanReadable::class, SOPGPException.UnsupportedOption::class)
|
||||||
fun withKeyPassword(password: ByteArray): UpdateKey
|
fun withKeyPassword(password: ByteArray): UpdateKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide certificates that might contain updated signatures or third-party certifications.
|
||||||
|
* These certificates will be merged into the key.
|
||||||
|
*
|
||||||
|
* @param certs input stream of certificates
|
||||||
|
*/
|
||||||
@Throws(
|
@Throws(
|
||||||
SOPGPException.UnsupportedOption::class, SOPGPException.BadData::class, IOException::class)
|
SOPGPException.UnsupportedOption::class, SOPGPException.BadData::class, IOException::class)
|
||||||
fun mergeCerts(certs: InputStream): UpdateKey
|
fun mergeCerts(certs: InputStream): UpdateKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide certificates that might contain updated signatures or third-party certifications.
|
||||||
|
* These certificates will be merged into the key.
|
||||||
|
*
|
||||||
|
* @param certs binary certificates
|
||||||
|
*/
|
||||||
@Throws(
|
@Throws(
|
||||||
SOPGPException.UnsupportedOption::class, SOPGPException.BadData::class, IOException::class)
|
SOPGPException.UnsupportedOption::class, SOPGPException.BadData::class, IOException::class)
|
||||||
fun mergeCerts(certs: ByteArray): UpdateKey = mergeCerts(certs.inputStream())
|
fun mergeCerts(certs: ByteArray): UpdateKey = mergeCerts(certs.inputStream())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide the OpenPGP key to update.
|
||||||
|
*
|
||||||
|
* @param key input stream containing the key
|
||||||
|
* @return handle to acquire the updated OpenPGP key from
|
||||||
|
*/
|
||||||
@Throws(
|
@Throws(
|
||||||
SOPGPException.BadData::class,
|
SOPGPException.BadData::class,
|
||||||
IOException::class,
|
IOException::class,
|
||||||
|
@ -45,6 +81,12 @@ interface UpdateKey {
|
||||||
SOPGPException.PrimaryKeyBad::class)
|
SOPGPException.PrimaryKeyBad::class)
|
||||||
fun key(key: InputStream): Ready
|
fun key(key: InputStream): Ready
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide the OpenPGP key to update.
|
||||||
|
*
|
||||||
|
* @param key binary OpenPGP key
|
||||||
|
* @return handle to acquire the updated OpenPGP key from
|
||||||
|
*/
|
||||||
@Throws(
|
@Throws(
|
||||||
SOPGPException.BadData::class,
|
SOPGPException.BadData::class,
|
||||||
IOException::class,
|
IOException::class,
|
||||||
|
|
|
@ -6,8 +6,8 @@ package sop.operation
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import sop.exception.SOPGPException
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import sop.exception.SOPGPException
|
||||||
|
|
||||||
/** Subcommand to validate UserIDs on certificates. */
|
/** Subcommand to validate UserIDs on certificates. */
|
||||||
interface ValidateUserId {
|
interface ValidateUserId {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue