1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-04-16 03:28:37 +02:00

Remove usage of deprecated methods in SOP implementations

This commit is contained in:
Paul Schaub 2025-03-28 16:02:36 +01:00
parent aaf7aa7ee9
commit b88440028a
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
11 changed files with 100 additions and 113 deletions

View file

@ -10,7 +10,6 @@ import java.io.OutputStream
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection
import org.pgpainless.PGPainless
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.exception.MissingPassphraseException
import org.pgpainless.key.protection.SecretKeyRingProtector
import org.pgpainless.key.util.KeyRingUtils
@ -29,30 +28,30 @@ class ChangeKeyPasswordImpl(private val api: PGPainless) : ChangeKeyPassword {
override fun keys(keys: InputStream): Ready {
val newProtector = SecretKeyRingProtector.unlockAnyKeyWith(newPassphrase)
val secretKeysCollection =
val secretKeys =
try {
KeyReader.readSecretKeys(keys, true)
KeyReader(api).readSecretKeys(keys, true)
} catch (e: IOException) {
throw SOPGPException.BadData(e)
}
val updatedSecretKeys =
secretKeysCollection
.map { secretKeys ->
oldProtector.addSecretKey(secretKeys)
secretKeys
.map {
oldProtector.addSecretKey(it)
try {
return@map KeyRingUtils.changePassphrase(
null, secretKeys, oldProtector, newProtector)
null, it.pgpSecretKeyRing, oldProtector, newProtector)
} catch (e: MissingPassphraseException) {
throw SOPGPException.KeyIsProtected(
"Cannot unlock key ${secretKeys.openPgpFingerprint}", e)
"Cannot unlock key ${it.keyIdentifier}", e)
} catch (e: PGPException) {
if (e.message?.contains("Exception decrypting key") == true) {
throw SOPGPException.KeyIsProtected(
"Cannot unlock key ${secretKeys.openPgpFingerprint}", e)
"Cannot unlock key ${it.keyIdentifier}", e)
}
throw RuntimeException(
"Cannot change passphrase of key ${secretKeys.openPgpFingerprint}", e)
"Cannot change passphrase of key ${it.keyIdentifier}", e)
}
}
.let { PGPSecretKeyRingCollection(it) }

View file

@ -92,11 +92,11 @@ class DecryptImpl(private val api: PGPainless) : Decrypt {
}
override fun verifyWithCert(cert: InputStream): Decrypt = apply {
KeyReader.readPublicKeys(cert, true).let { consumerOptions.addVerificationCerts(it) }
consumerOptions.addVerificationCerts(KeyReader(api).readPublicKeys(cert, true))
}
override fun withKey(key: InputStream): Decrypt = apply {
KeyReader.readSecretKeys(key, true).forEach {
KeyReader(api).readSecretKeys(key, true).forEach {
protector.addSecretKey(it)
consumerOptions.addDecryptionKey(it, protector)
}

View file

@ -7,14 +7,13 @@ package org.pgpainless.sop
import java.io.InputStream
import java.io.OutputStream
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.DocumentSignatureType
import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.encryption_signing.ProducerOptions
import org.pgpainless.encryption_signing.SigningOptions
import org.pgpainless.exception.KeyException.MissingSecretKeyException
@ -34,7 +33,7 @@ class DetachedSignImpl(private val api: PGPainless) : DetachedSign {
private val signingOptions = SigningOptions.get(api)
private val protector = MatchMakingSecretKeyRingProtector()
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
private val signingKeys = mutableListOf<OpenPGPKey>()
private var armor = true
private var mode = SignAs.binary
@ -44,13 +43,13 @@ class DetachedSignImpl(private val api: PGPainless) : DetachedSign {
try {
signingOptions.addDetachedSignature(protector, it, modeToSigType(mode))
} catch (e: UnacceptableSigningKeyException) {
throw SOPGPException.KeyCannotSign("Key ${it.openPgpFingerprint} cannot sign.", e)
throw SOPGPException.KeyCannotSign("Key ${it.keyIdentifier} cannot sign.", e)
} catch (e: MissingSecretKeyException) {
throw SOPGPException.KeyCannotSign(
"Key ${it.openPgpFingerprint} cannot sign. Missing secret key.", e)
"Key ${it.keyIdentifier} cannot sign. Missing secret key.", e)
} catch (e: PGPException) {
throw SOPGPException.KeyIsProtected(
"Key ${it.openPgpFingerprint} cannot be unlocked.", e)
"Key ${it.keyIdentifier} cannot be unlocked.", e)
}
}
@ -93,8 +92,8 @@ class DetachedSignImpl(private val api: PGPainless) : DetachedSign {
}
override fun key(key: InputStream): DetachedSign = apply {
KeyReader.readSecretKeys(key, true).forEach {
val info = api.inspect(api.toKey(it))
KeyReader(api).readSecretKeys(key, true).forEach {
val info = api.inspect(it)
if (!info.isUsableForSigning) {
throw SOPGPException.KeyCannotSign(
"Key ${info.fingerprint} does not have valid, signing capable subkeys.")

View file

@ -23,7 +23,7 @@ class DetachedVerifyImpl(private val api: PGPainless) : DetachedVerify {
private val options = ConsumerOptions.get(api).forceNonOpenPgpData()
override fun cert(cert: InputStream): DetachedVerify = apply {
options.addVerificationCerts(KeyReader.readPublicKeys(cert, true))
options.addVerificationCerts(KeyReader(api).readPublicKeys(cert, true))
}
override fun data(data: InputStream): List<Verification> {

View file

@ -8,12 +8,11 @@ import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.algorithm.DocumentSignatureType
import org.pgpainless.algorithm.StreamEncoding
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.encryption_signing.EncryptionOptions
import org.pgpainless.encryption_signing.ProducerOptions
import org.pgpainless.encryption_signing.SigningOptions
@ -40,7 +39,7 @@ class EncryptImpl(private val api: PGPainless) : Encrypt {
private val encryptionOptions = EncryptionOptions.get(api)
private var signingOptions: SigningOptions? = null
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
private val signingKeys = mutableListOf<OpenPGPKey>()
private val protector = MatchMakingSecretKeyRingProtector()
private var profile = RFC4880_PROFILE.name
@ -69,9 +68,9 @@ class EncryptImpl(private val api: PGPainless) : Encrypt {
try {
signingOptions!!.addInlineSignature(protector, it, modeToSignatureType(mode))
} catch (e: UnacceptableSigningKeyException) {
throw SOPGPException.KeyCannotSign("Key ${it.openPgpFingerprint} cannot sign", e)
throw SOPGPException.KeyCannotSign("Key ${it.keyIdentifier} cannot sign", e)
} catch (e: WrongPassphraseException) {
throw SOPGPException.KeyIsProtected("Cannot unlock key ${it.openPgpFingerprint}", e)
throw SOPGPException.KeyIsProtected("Cannot unlock key ${it.keyIdentifier}", e)
} catch (e: PGPException) {
throw SOPGPException.BadData(e)
}
@ -105,14 +104,14 @@ class EncryptImpl(private val api: PGPainless) : Encrypt {
}
val signingKey =
KeyReader.readSecretKeys(key, true).singleOrNull()
KeyReader(api).readSecretKeys(key, true).singleOrNull()
?: throw SOPGPException.BadData(
AssertionError(
"Exactly one secret key at a time expected. Got zero or multiple instead."))
val info = api.inspect(api.toKey(signingKey))
val info = api.inspect(signingKey)
if (info.signingSubkeys.isEmpty()) {
throw SOPGPException.KeyCannotSign("Key ${info.fingerprint} cannot sign.")
throw SOPGPException.KeyCannotSign("Key ${info.keyIdentifier} cannot sign.")
}
protector.addSecretKey(signingKey)
@ -121,7 +120,7 @@ class EncryptImpl(private val api: PGPainless) : Encrypt {
override fun withCert(cert: InputStream): Encrypt = apply {
try {
encryptionOptions.addRecipients(KeyReader.readPublicKeys(cert, true))
KeyReader(api).readPublicKeys(cert, true).forEach { encryptionOptions.addRecipient(it) }
} catch (e: UnacceptableEncryptionKeyException) {
throw SOPGPException.CertCannotEncrypt(e.message ?: "Cert cannot encrypt", e)
} catch (e: IOException) {

View file

@ -18,8 +18,7 @@ class ExtractCertImpl(private val api: PGPainless) : ExtractCert {
private var armor = true
override fun key(keyInputStream: InputStream): Ready {
val certs =
KeyReader.readSecretKeys(keyInputStream, true).map { PGPainless.extractCertificate(it) }
val certs = KeyReader(api).readSecretKeys(keyInputStream, true).map { it.toCertificate() }
return object : Ready() {
override fun writeTo(outputStream: OutputStream) {
@ -27,17 +26,18 @@ class ExtractCertImpl(private val api: PGPainless) : ExtractCert {
if (certs.size == 1) {
val cert = certs[0]
// This way we have a nice armor header with fingerprint and user-ids
val armorOut = ArmorUtils.toAsciiArmoredStream(cert, outputStream)
cert.encode(armorOut)
val armorOut =
ArmorUtils.toAsciiArmoredStream(cert.pgpKeyRing, outputStream)
armorOut.write(cert.encoded)
armorOut.close()
} else {
// for multiple certs, add no info headers to the ASCII armor
val armorOut = ArmoredOutputStreamFactory.get(outputStream)
certs.forEach { it.encode(armorOut) }
certs.forEach { armorOut.write(it.encoded) }
armorOut.close()
}
} else {
certs.forEach { it.encode(outputStream) }
certs.forEach { outputStream.write(it.encoded) }
}
}
}

View file

@ -8,13 +8,12 @@ import java.io.InputStream
import java.io.OutputStream
import java.lang.RuntimeException
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.util.io.Streams
import org.pgpainless.PGPainless
import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.DocumentSignatureType
import org.pgpainless.algorithm.StreamEncoding
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.encryption_signing.ProducerOptions
import org.pgpainless.encryption_signing.SigningOptions
import org.pgpainless.exception.KeyException.MissingSecretKeyException
@ -31,7 +30,7 @@ class InlineSignImpl(private val api: PGPainless) : InlineSign {
private val signingOptions = SigningOptions.get(api)
private val protector = MatchMakingSecretKeyRingProtector()
private val signingKeys = mutableListOf<PGPSecretKeyRing>()
private val signingKeys = mutableListOf<OpenPGPKey>()
private var armor = true
private var mode = InlineSignAs.binary
@ -45,14 +44,14 @@ class InlineSignImpl(private val api: PGPainless) : InlineSign {
signingOptions.addInlineSignature(protector, key, modeToSigType(mode))
}
} catch (e: UnacceptableSigningKeyException) {
throw SOPGPException.KeyCannotSign("Key ${key.openPgpFingerprint} cannot sign.", e)
throw SOPGPException.KeyCannotSign("Key ${key.keyIdentifier} cannot sign.", e)
} catch (e: MissingSecretKeyException) {
throw SOPGPException.KeyCannotSign(
"Key ${key.openPgpFingerprint} does not have the secret signing key component available.",
"Key ${key.keyIdentifier} does not have the secret signing key component available.",
e)
} catch (e: PGPException) {
throw SOPGPException.KeyIsProtected(
"Key ${key.openPgpFingerprint} cannot be unlocked.", e)
"Key ${key.keyIdentifier} cannot be unlocked.", e)
}
}
@ -97,11 +96,11 @@ class InlineSignImpl(private val api: PGPainless) : InlineSign {
}
override fun key(key: InputStream): InlineSign = apply {
KeyReader.readSecretKeys(key, true).forEach {
val info = api.inspect(api.toKey(it))
KeyReader(api).readSecretKeys(key, true).forEach {
val info = api.inspect(it)
if (!info.isUsableForSigning) {
throw SOPGPException.KeyCannotSign(
"Key ${info.fingerprint} does not have valid, signing capable subkeys.")
"Key ${info.keyIdentifier} does not have valid, signing capable subkeys.")
}
protector.addSecretKey(it)
signingKeys.add(it)

View file

@ -24,7 +24,7 @@ class InlineVerifyImpl(private val api: PGPainless) : InlineVerify {
private val options = ConsumerOptions.get(api)
override fun cert(cert: InputStream): InlineVerify = apply {
options.addVerificationCerts(KeyReader.readPublicKeys(cert, true))
options.addVerificationCerts(KeyReader(api).readPublicKeys(cert, true))
}
override fun data(data: InputStream): ReadyWithResult<List<Verification>> {

View file

@ -7,71 +7,63 @@ package org.pgpainless.sop
import java.io.IOException
import java.io.InputStream
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection
import org.bouncycastle.openpgp.PGPRuntimeOperationException
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.pgpainless.PGPainless
import sop.exception.SOPGPException
/** Reader for OpenPGP keys and certificates with error matching according to the SOP spec. */
class KeyReader {
class KeyReader(val api: PGPainless = PGPainless.getInstance()) {
companion object {
@JvmStatic
fun readSecretKeys(
keyInputStream: InputStream,
requireContent: Boolean
): PGPSecretKeyRingCollection {
val keys =
try {
PGPainless.readKeyRing().secretKeyRingCollection(keyInputStream)
} catch (e: IOException) {
if (e.message == null) {
throw e
}
if (e.message!!.startsWith("unknown object in stream:") ||
e.message!!.startsWith("invalid header encountered")) {
throw SOPGPException.BadData(e)
}
fun readSecretKeys(keyInputStream: InputStream, requireContent: Boolean): List<OpenPGPKey> {
val keys =
try {
api.readKey().parseKeys(keyInputStream)
} catch (e: IOException) {
if (e.message == null) {
throw e
}
if (requireContent && keys.none()) {
throw SOPGPException.BadData(PGPException("No key data found."))
}
return keys
}
@JvmStatic
fun readPublicKeys(
certIn: InputStream,
requireContent: Boolean
): PGPPublicKeyRingCollection {
val certs =
try {
PGPainless.readKeyRing().keyRingCollection(certIn, true)
} catch (e: IOException) {
if (e.message == null) {
throw e
}
if (e.message!!.startsWith("unknown object in stream:") ||
e.message!!.startsWith("invalid header encountered")) {
throw SOPGPException.BadData(e)
}
throw e
} catch (e: PGPRuntimeOperationException) {
if (e.message!!.startsWith("unknown object in stream:") ||
e.message!!.startsWith("invalid header encountered") ||
e.message!!.startsWith("Encountered unexpected packet:")) {
throw SOPGPException.BadData(e)
}
if (certs.pgpSecretKeyRingCollection.any()) {
throw SOPGPException.BadData(
"Secret key components encountered, while certificates were expected.")
throw e
}
if (requireContent && certs.pgpPublicKeyRingCollection.none()) {
throw SOPGPException.BadData(PGPException("No cert data found."))
}
return certs.pgpPublicKeyRingCollection
if (requireContent && keys.none()) {
throw SOPGPException.BadData(PGPException("No key data found."))
}
return keys
}
fun readPublicKeys(certIn: InputStream, requireContent: Boolean): List<OpenPGPCertificate> {
val certs =
try {
api.readKey().parseKeysOrCertificates(certIn)
} catch (e: IOException) {
if (e.message == null) {
throw e
}
if (e.message!!.startsWith("unknown object in stream:") ||
e.message!!.startsWith("invalid header encountered")) {
throw SOPGPException.BadData(e)
}
throw e
} catch (e: PGPRuntimeOperationException) {
throw SOPGPException.BadData(e)
}
if (certs.any { it.isSecretKey }) {
throw SOPGPException.BadData(
"Secret key components encountered, while certificates were expected.")
}
if (requireContent && certs.isEmpty()) {
throw SOPGPException.BadData("No certificate data found.")
}
return certs
}
}

View file

@ -39,7 +39,7 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
keys.forEach { key ->
for (subkey in key) {
if (protector.hasPassphrase(subkey.keyID)) {
if (protector.hasPassphrase(subkey.keyIdentifier)) {
continue
}
@ -50,6 +50,8 @@ class MatchMakingSecretKeyRingProtector : SecretKeyRingProtector {
}
}
fun addSecretKey(key: OpenPGPKey) = addSecretKey(key.pgpSecretKeyRing)
fun addSecretKey(key: PGPSecretKeyRing) = apply {
if (!keys.add(key)) {
return@apply

View file

@ -12,7 +12,6 @@ import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.pgpainless.PGPainless
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.bouncycastle.extensions.toOpenPGPCertificate
import org.pgpainless.exception.WrongPassphraseException
import org.pgpainless.key.util.KeyRingUtils
@ -30,29 +29,28 @@ class RevokeKeyImpl(private val api: PGPainless) : RevokeKey {
private var armor = true
override fun keys(keys: InputStream): Ready {
val secretKeyRings =
val secretKeys =
try {
KeyReader.readSecretKeys(keys, true)
KeyReader(api).readSecretKeys(keys, true)
} catch (e: IOException) {
throw SOPGPException.BadData("Cannot decode secret keys.", e)
}
secretKeyRings.forEach { protector.addSecretKey(it) }
secretKeys.forEach { protector.addSecretKey(it) }
val revocationCertificates = mutableListOf<OpenPGPCertificate>()
secretKeyRings.forEach { secretKeys ->
val openPGPKey = api.toKey(secretKeys)
val editor = api.modify(openPGPKey)
secretKeys.forEach {
val editor = api.modify(it)
try {
val attributes =
RevocationAttributes.createKeyRevocation()
.withReason(RevocationAttributes.Reason.NO_REASON)
.withoutDescription()
if (openPGPKey.primaryKey.version == 6) {
if (it.primaryKey.version == 6) {
revocationCertificates.add(
editor.createMinimalRevocationCertificate(protector, attributes))
} else {
val certificate = openPGPKey.toCertificate()
val certificate = it.toCertificate()
val revocation = editor.createRevocation(protector, attributes)
revocationCertificates.add(
KeyRingUtils.injectCertification(
@ -61,11 +59,10 @@ class RevokeKeyImpl(private val api: PGPainless) : RevokeKey {
}
} catch (e: WrongPassphraseException) {
throw SOPGPException.KeyIsProtected(
"Missing or wrong passphrase for key ${secretKeys.openPgpFingerprint}", e)
"Missing or wrong passphrase for key ${it.keyIdentifier}", e)
} catch (e: PGPException) {
throw RuntimeException(
"Cannot generate revocation certificate for key ${secretKeys.openPgpFingerprint}",
e)
"Cannot generate revocation certificate for key ${it.keyIdentifier}", e)
}
}