mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Port ConsumerOptions, SigningOptions to new OpenPGPCertificate, OpenPGPKey classes
This commit is contained in:
parent
bbecdd693f
commit
4a90b8721f
6 changed files with 260 additions and 150 deletions
|
@ -12,6 +12,7 @@ import org.bouncycastle.openpgp.*
|
|||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy
|
||||
|
@ -73,12 +74,20 @@ class ConsumerOptions {
|
|||
this.certificates.addCertificate(verificationCert)
|
||||
}
|
||||
|
||||
fun addVerificationCerts(verificationCerts: Collection<OpenPGPCertificate>): ConsumerOptions =
|
||||
apply {
|
||||
for (cert in verificationCerts) {
|
||||
addVerificationCert(cert)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a certificate (public key ring) for signature verification.
|
||||
*
|
||||
* @param verificationCert certificate for signature verification
|
||||
* @return options
|
||||
*/
|
||||
@Deprecated("Pass OpenPGPCertificate instead.")
|
||||
fun addVerificationCert(verificationCert: PGPPublicKeyRing): ConsumerOptions = apply {
|
||||
this.certificates.addCertificate(verificationCert)
|
||||
}
|
||||
|
@ -89,6 +98,7 @@ class ConsumerOptions {
|
|||
* @param verificationCerts certificates for signature verification
|
||||
* @return options
|
||||
*/
|
||||
@Deprecated("Use of methods taking PGPPublicKeyRingCollections is discouraged.")
|
||||
fun addVerificationCerts(verificationCerts: PGPPublicKeyRingCollection): ConsumerOptions =
|
||||
apply {
|
||||
for (cert in verificationCerts) {
|
||||
|
@ -125,6 +135,14 @@ class ConsumerOptions {
|
|||
}
|
||||
}
|
||||
|
||||
fun addVerificationOfDetachedSignature(signature: OpenPGPDocumentSignature): ConsumerOptions =
|
||||
apply {
|
||||
if (signature.issuerCertificate != null) {
|
||||
addVerificationCert(signature.issuerCertificate)
|
||||
}
|
||||
addVerificationOfDetachedSignature(signature.signature)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a detached signature for the signature verification process.
|
||||
*
|
||||
|
@ -178,6 +196,7 @@ class ConsumerOptions {
|
|||
* @return options
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Deprecated("Pass OpenPGPKey instead.")
|
||||
fun addDecryptionKey(
|
||||
key: PGPSecretKeyRing,
|
||||
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys(),
|
||||
|
@ -192,6 +211,7 @@ class ConsumerOptions {
|
|||
* @return options
|
||||
*/
|
||||
@JvmOverloads
|
||||
@Deprecated("Pass OpenPGPKey instances instead.")
|
||||
fun addDecryptionKeys(
|
||||
keys: PGPSecretKeyRingCollection,
|
||||
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||
|
@ -201,21 +221,6 @@ class ConsumerOptions {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a passphrase for message decryption. This passphrase will be used to try to decrypt
|
||||
* messages which were symmetrically encrypted for a passphrase.
|
||||
*
|
||||
* See
|
||||
* [Symmetrically Encrypted Data Packet](https://datatracker.ietf.org/doc/html/rfc4880#section-5.7)
|
||||
*
|
||||
* @param passphrase passphrase
|
||||
* @return options
|
||||
*/
|
||||
@Deprecated(
|
||||
"Deprecated in favor of addMessagePassphrase",
|
||||
ReplaceWith("addMessagePassphrase(passphrase)"))
|
||||
fun addDecryptionPassphrase(passphrase: Passphrase) = addMessagePassphrase(passphrase)
|
||||
|
||||
/**
|
||||
* Add a passphrase for message decryption. This passphrase will be used to try to decrypt
|
||||
* messages which were symmetrically encrypted for a passphrase.
|
||||
|
@ -255,21 +260,21 @@ class ConsumerOptions {
|
|||
*
|
||||
* @return decryption keys
|
||||
*/
|
||||
fun getDecryptionKeys() = decryptionKeys.keys.toSet()
|
||||
fun getDecryptionKeys(): Set<OpenPGPKey> = decryptionKeys.keys.toSet()
|
||||
|
||||
/**
|
||||
* Return the set of available message decryption passphrases.
|
||||
*
|
||||
* @return decryption passphrases
|
||||
*/
|
||||
fun getDecryptionPassphrases() = decryptionPassphrases.toSet()
|
||||
fun getDecryptionPassphrases(): Set<Passphrase> = decryptionPassphrases.toSet()
|
||||
|
||||
/**
|
||||
* Return an object holding available certificates for signature verification.
|
||||
*
|
||||
* @return certificate source
|
||||
*/
|
||||
fun getCertificateSource() = certificates
|
||||
fun getCertificateSource(): CertificateSource = certificates
|
||||
|
||||
/**
|
||||
* Return the callback that gets called when a certificate for signature verification is
|
||||
|
@ -277,7 +282,7 @@ class ConsumerOptions {
|
|||
*
|
||||
* @return missing public key callback
|
||||
*/
|
||||
fun getMissingCertificateCallback() = missingCertificateCallback
|
||||
fun getMissingCertificateCallback(): MissingPublicKeyCallback? = missingCertificateCallback
|
||||
|
||||
/**
|
||||
* Return the [SecretKeyRingProtector] for the given [PGPSecretKeyRing].
|
||||
|
@ -321,7 +326,7 @@ class ConsumerOptions {
|
|||
this.ignoreMDCErrors = ignoreMDCErrors
|
||||
}
|
||||
|
||||
fun isIgnoreMDCErrors() = ignoreMDCErrors
|
||||
fun isIgnoreMDCErrors(): Boolean = ignoreMDCErrors
|
||||
|
||||
/**
|
||||
* Force PGPainless to handle the data provided by the [InputStream] as non-OpenPGP data. This
|
||||
|
@ -337,7 +342,7 @@ class ConsumerOptions {
|
|||
*
|
||||
* @return true if non-OpenPGP data is forced
|
||||
*/
|
||||
fun isForceNonOpenPgpData() = forceNonOpenPgpData
|
||||
fun isForceNonOpenPgpData(): Boolean = forceNonOpenPgpData
|
||||
|
||||
/**
|
||||
* Specify the [MissingKeyPassphraseStrategy]. This strategy defines, how missing passphrases
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData
|
|||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature.OpenPGPDocumentSignature
|
||||
import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory
|
||||
|
@ -58,6 +59,7 @@ import org.pgpainless.exception.UnacceptableAlgorithmException
|
|||
import org.pgpainless.exception.WrongPassphraseException
|
||||
import org.pgpainless.implementation.ImplementationFactory
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
import org.pgpainless.key.protection.UnlockSecretKey.Companion.unlockSecretKey
|
||||
import org.pgpainless.policy.Policy
|
||||
import org.pgpainless.signature.consumer.CertificateValidator
|
||||
import org.pgpainless.signature.consumer.OnePassSignatureCheck
|
||||
|
@ -420,10 +422,15 @@ class OpenPgpMessageInputStream(
|
|||
continue
|
||||
}
|
||||
|
||||
val privateKey = secretKey.unlock(protector)
|
||||
val privateKey =
|
||||
try {
|
||||
unlockSecretKey(secretKey, protector)
|
||||
} catch (e: PGPException) {
|
||||
throw WrongPassphraseException(secretKey.keyIdentifier, e)
|
||||
}
|
||||
if (decryptWithPrivateKey(
|
||||
esks,
|
||||
privateKey,
|
||||
privateKey.unlockedKey,
|
||||
SubkeyIdentifier(
|
||||
secretKey.openPGPKey.pgpSecretKeyRing, secretKey.keyIdentifier),
|
||||
pkesk)) {
|
||||
|
@ -451,7 +458,7 @@ class OpenPgpMessageInputStream(
|
|||
|
||||
val privateKey = decryptionKey.unlock(protector)
|
||||
if (decryptWithPrivateKey(
|
||||
esks, privateKey, SubkeyIdentifier(decryptionKey), pkesk)) {
|
||||
esks, privateKey.unlockedKey, SubkeyIdentifier(decryptionKey), pkesk)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -476,13 +483,13 @@ class OpenPgpMessageInputStream(
|
|||
LOGGER.debug(
|
||||
"Attempt decryption with key $decryptionKeyId while interactively requesting its passphrase.")
|
||||
val protector = options.getSecretKeyProtector(decryptionKeys) ?: continue
|
||||
val privateKey =
|
||||
val privateKey: OpenPGPPrivateKey =
|
||||
try {
|
||||
secretKey.unlock(protector)
|
||||
unlockSecretKey(secretKey, protector)
|
||||
} catch (e: PGPException) {
|
||||
throw WrongPassphraseException(secretKey.keyIdentifier, e)
|
||||
}
|
||||
if (decryptWithPrivateKey(esks, privateKey, decryptionKeyId, pkesk)) {
|
||||
if (decryptWithPrivateKey(esks, privateKey.unlockedKey, decryptionKeyId, pkesk)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.pgpainless.algorithm.CompressionAlgorithm
|
|||
import org.pgpainless.algorithm.StreamEncoding
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||
import org.pgpainless.implementation.ImplementationFactory
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
import org.pgpainless.util.ArmoredOutputStreamFactory
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
@ -250,7 +251,7 @@ class EncryptionStream(
|
|||
options.signingOptions.signingMethods.entries.reversed().forEach { (key, method) ->
|
||||
method.signatureGenerator.generate().let { sig ->
|
||||
if (method.isDetached) {
|
||||
resultBuilder.addDetachedSignature(key, sig)
|
||||
resultBuilder.addDetachedSignature(SubkeyIdentifier(key), sig)
|
||||
}
|
||||
if (!method.isDetached || options.isCleartextSigned) {
|
||||
sig.encode(signatureLayerStream)
|
||||
|
|
|
@ -7,19 +7,22 @@ package org.pgpainless.encryption_signing
|
|||
import java.util.*
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.openpgp.*
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
import org.pgpainless.PGPainless.Companion.getPolicy
|
||||
import org.pgpainless.PGPainless.Companion.inspectKeyRing
|
||||
import org.pgpainless.algorithm.DocumentSignatureType
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm.Companion.requireFromId
|
||||
import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator.Companion.negotiateSignatureHashAlgorithm
|
||||
import org.pgpainless.bouncycastle.extensions.unlock
|
||||
import org.pgpainless.bouncycastle.extensions.toOpenPGPKey
|
||||
import org.pgpainless.exception.KeyException
|
||||
import org.pgpainless.exception.KeyException.*
|
||||
import org.pgpainless.implementation.ImplementationFactory
|
||||
import org.pgpainless.key.OpenPgpFingerprint.Companion.of
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector
|
||||
import org.pgpainless.key.protection.UnlockSecretKey.Companion.unlockSecretKey
|
||||
import org.pgpainless.policy.Policy
|
||||
import org.pgpainless.signature.subpackets.BaseSignatureSubpackets.Callback
|
||||
import org.pgpainless.signature.subpackets.SignatureSubpackets
|
||||
|
@ -27,7 +30,7 @@ import org.pgpainless.signature.subpackets.SignatureSubpacketsHelper
|
|||
|
||||
class SigningOptions {
|
||||
|
||||
val signingMethods: Map<SubkeyIdentifier, SigningMethod> = mutableMapOf()
|
||||
val signingMethods: Map<OpenPGPPrivateKey, SigningMethod> = mutableMapOf()
|
||||
private var _hashAlgorithmOverride: HashAlgorithm? = null
|
||||
private var _evaluationDate: Date = Date()
|
||||
|
||||
|
@ -62,18 +65,34 @@ class SigningOptions {
|
|||
* Sign the message using an inline signature made by the provided signing key.
|
||||
*
|
||||
* @param signingKeyProtector protector to unlock the signing key
|
||||
* @param signingKey key ring containing the signing key
|
||||
* @param signingKey OpenPGPKey containing the signing (sub-)key.
|
||||
* @return this
|
||||
* @throws KeyException if something is wrong with the key
|
||||
* @throws PGPException if the key cannot be unlocked or a signing method cannot be created
|
||||
*/
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
fun addSignature(signingKeyProtector: SecretKeyRingProtector, signingKey: PGPSecretKeyRing) =
|
||||
apply {
|
||||
fun addSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey
|
||||
): SigningOptions = apply {
|
||||
addInlineSignature(
|
||||
signingKeyProtector, signingKey, null, DocumentSignatureType.BINARY_DOCUMENT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the message using an inline signature made by the provided signing key.
|
||||
*
|
||||
* @param signingKeyProtector protector to unlock the signing key
|
||||
* @param signingKey key ring containing the signing key
|
||||
* @return this
|
||||
* @throws KeyException if something is wrong with the key
|
||||
* @throws PGPException if the key cannot be unlocked or a signing method cannot be created
|
||||
*/
|
||||
@Deprecated("Pass an OpenPGPKey instead.")
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
fun addSignature(signingKeyProtector: SecretKeyRingProtector, signingKey: PGPSecretKeyRing) =
|
||||
addSignature(signingKeyProtector, signingKey.toOpenPGPKey())
|
||||
|
||||
/**
|
||||
* Add inline signatures with all secret key rings in the provided secret key ring collection.
|
||||
*
|
||||
|
@ -86,6 +105,7 @@ class SigningOptions {
|
|||
* created
|
||||
*/
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
@Deprecated("Repeatedly call addInlineSignature(), passing an OpenPGPKey instead.")
|
||||
fun addInlineSignatures(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKeys: Iterable<PGPSecretKeyRing>,
|
||||
|
@ -94,6 +114,12 @@ class SigningOptions {
|
|||
signingKeys.forEach { addInlineSignature(signingKeyProtector, it, null, signatureType) }
|
||||
}
|
||||
|
||||
fun addInlineSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT
|
||||
): SigningOptions = addInlineSignature(signingKeyProtector, signingKey, null, signatureType)
|
||||
|
||||
/**
|
||||
* Add an inline-signature. Inline signatures are being embedded into the message itself and can
|
||||
* be processed in one pass, thanks to the use of one-pass-signature packets.
|
||||
|
@ -106,11 +132,49 @@ class SigningOptions {
|
|||
* @throws PGPException if the key cannot be unlocked or the signing method cannot be created
|
||||
*/
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
@Deprecated("Pass an OpenPGPKey instead.")
|
||||
fun addInlineSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: PGPSecretKeyRing,
|
||||
signatureType: DocumentSignatureType
|
||||
) = apply { addInlineSignature(signingKeyProtector, signingKey, null, signatureType) }
|
||||
) = addInlineSignature(signingKeyProtector, signingKey.toOpenPGPKey(), signatureType)
|
||||
|
||||
fun addInlineSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey,
|
||||
userId: CharSequence? = null,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey.pgpSecretKeyRing),
|
||||
userId.toString(),
|
||||
keyRingInfo.getLatestUserIdCertification(userId),
|
||||
keyRingInfo.getUserIdRevocation(userId))
|
||||
}
|
||||
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey.pgpSecretKeyRing))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
val signingSecKey: OpenPGPSecretKey =
|
||||
signingKey.getSecretKey(signingPubKey)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey.pgpSecretKeyRing), signingPubKey.keyIdentifier.keyId)
|
||||
val signingPrivKey: OpenPGPPrivateKey =
|
||||
unlockSecretKey(signingSecKey, signingKeyProtector)
|
||||
val hashAlgorithms =
|
||||
if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId)
|
||||
else keyRingInfo.getPreferredHashAlgorithms(signingPubKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(
|
||||
signingPrivKey, hashAlgorithm, signatureType, false, subpacketsCallback)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an inline-signature. Inline signatures are being embedded into the message itself and can
|
||||
|
@ -129,6 +193,7 @@ class SigningOptions {
|
|||
* @throws KeyException if the key is invalid
|
||||
* @throws PGPException if the key cannot be unlocked or the signing method cannot be created
|
||||
*/
|
||||
@Deprecated("Pass an OpenPGPKey instead.")
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
@JvmOverloads
|
||||
fun addInlineSignature(
|
||||
|
@ -137,34 +202,36 @@ class SigningOptions {
|
|||
userId: CharSequence? = null,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey),
|
||||
userId.toString(),
|
||||
keyRingInfo.getLatestUserIdCertification(userId),
|
||||
keyRingInfo.getUserIdRevocation(userId))
|
||||
}
|
||||
) =
|
||||
addInlineSignature(
|
||||
signingKeyProtector,
|
||||
signingKey.toOpenPGPKey(),
|
||||
userId,
|
||||
signatureType,
|
||||
subpacketsCallback)
|
||||
|
||||
fun addInlineSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPSecretKey,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val openPGPKey = signingKey.openPGPKey
|
||||
val keyRingInfo = inspectKeyRing(openPGPKey, evaluationDate)
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey))
|
||||
throw UnacceptableSigningKeyException(of(openPGPKey.pgpSecretKeyRing))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
val signingSecKey: PGPSecretKey =
|
||||
signingKey.getSecretKey(signingPubKey.keyIdentifier)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey), signingPubKey.keyIdentifier.keyId)
|
||||
val signingSubkey: PGPPrivateKey = signingSecKey.unlock(signingKeyProtector)
|
||||
val hashAlgorithms =
|
||||
if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId)
|
||||
else keyRingInfo.getPreferredHashAlgorithms(signingPubKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(
|
||||
signingKey, signingSubkey, hashAlgorithm, signatureType, false, subpacketsCallback)
|
||||
if (!signingPubKeys.any { it.keyIdentifier.matches(signingKey.keyIdentifier) }) {
|
||||
throw MissingSecretKeyException(
|
||||
of(openPGPKey.pgpSecretKeyRing), signingKey.keyIdentifier.keyId)
|
||||
}
|
||||
|
||||
val signingPrivKey = unlockSecretKey(signingKey, signingKeyProtector)
|
||||
val hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(signingKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(signingPrivKey, hashAlgorithm, signatureType, false, subpacketsCallback)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,31 +258,13 @@ class SigningOptions {
|
|||
keyId: Long,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
if (!signingPubKey.keyIdentifier.matches(KeyIdentifier(keyId))) {
|
||||
continue
|
||||
}
|
||||
|
||||
val signingSecKey =
|
||||
signingKey.getSecretKey(signingPubKey.keyIdentifier)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey), signingPubKey.keyIdentifier.keyId)
|
||||
val signingSubkey = signingSecKey.unlock(signingKeyProtector)
|
||||
val hashAlgorithms = keyRingInfo.getPreferredHashAlgorithms(signingPubKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(
|
||||
signingKey, signingSubkey, hashAlgorithm, signatureType, false, subpacketsCallback)
|
||||
return this
|
||||
}
|
||||
throw MissingSecretKeyException(of(signingKey), keyId)
|
||||
}
|
||||
) =
|
||||
addInlineSignature(
|
||||
signingKeyProtector,
|
||||
signingKey.toOpenPGPKey().getSecretKey(KeyIdentifier(keyId))
|
||||
?: throw MissingSecretKeyException(of(signingKey), keyId),
|
||||
signatureType,
|
||||
subpacketsCallback)
|
||||
|
||||
/**
|
||||
* Add detached signatures with all key rings from the provided secret key ring collection.
|
||||
|
@ -229,6 +278,7 @@ class SigningOptions {
|
|||
* method cannot be created
|
||||
*/
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
@Deprecated("Repeatedly call addDetachedSignature(), passing an OpenPGPKey instead.")
|
||||
fun addDetachedSignatures(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKeys: Iterable<PGPSecretKeyRing>,
|
||||
|
@ -237,6 +287,12 @@ class SigningOptions {
|
|||
signingKeys.forEach { addDetachedSignature(signingKeyProtector, it, null, signatureType) }
|
||||
}
|
||||
|
||||
fun addDetachedSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT
|
||||
): SigningOptions = addDetachedSignature(signingKeyProtector, signingKey, null, signatureType)
|
||||
|
||||
/**
|
||||
* Create a detached signature. Detached signatures are not being added into the PGP message
|
||||
* itself. Instead, they can be distributed separately to the message. Detached signatures are
|
||||
|
@ -250,6 +306,7 @@ class SigningOptions {
|
|||
* @throws PGPException if the key cannot be validated or unlocked, or if no signature method
|
||||
* can be created
|
||||
*/
|
||||
@Deprecated("Pass an OpenPGPKey instead.")
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
fun addDetachedSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
|
@ -257,6 +314,37 @@ class SigningOptions {
|
|||
signatureType: DocumentSignatureType
|
||||
) = apply { addDetachedSignature(signingKeyProtector, signingKey, null, signatureType) }
|
||||
|
||||
fun addDetachedSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey,
|
||||
userId: CharSequence? = null,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey.pgpSecretKeyRing),
|
||||
userId.toString(),
|
||||
keyRingInfo.getLatestUserIdCertification(userId),
|
||||
keyRingInfo.getUserIdRevocation(userId))
|
||||
}
|
||||
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey.pgpSecretKeyRing))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
val signingSecKey: OpenPGPSecretKey =
|
||||
signingKey.getSecretKey(signingPubKey.keyIdentifier)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey.pgpSecretKeyRing), signingPubKey.keyIdentifier.keyId)
|
||||
addDetachedSignature(
|
||||
signingKeyProtector, signingSecKey, userId, signatureType, subpacketCallback)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a detached signature. Detached signatures are not being added into the PGP message
|
||||
* itself. Instead, they can be distributed separately to the message. Detached signatures are
|
||||
|
@ -275,6 +363,7 @@ class SigningOptions {
|
|||
* @throws PGPException if the key cannot be validated or unlocked, or if no signature method
|
||||
* can be created
|
||||
*/
|
||||
@Deprecated("Pass an OpenPGPKey instead.")
|
||||
@JvmOverloads
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
fun addDetachedSignature(
|
||||
|
@ -283,34 +372,28 @@ class SigningOptions {
|
|||
userId: String? = null,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey),
|
||||
userId.toString(),
|
||||
keyRingInfo.getLatestUserIdCertification(userId),
|
||||
keyRingInfo.getUserIdRevocation(userId))
|
||||
}
|
||||
) =
|
||||
addDetachedSignature(
|
||||
signingKeyProtector,
|
||||
signingKey.toOpenPGPKey(),
|
||||
userId,
|
||||
signatureType,
|
||||
subpacketCallback)
|
||||
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
val signingSecKey: PGPSecretKey =
|
||||
signingKey.getSecretKey(signingPubKey.keyIdentifier)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey), signingPubKey.keyIdentifier.keyId)
|
||||
val signingSubkey: PGPPrivateKey = signingSecKey.unlock(signingKeyProtector)
|
||||
fun addDetachedSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPSecretKey,
|
||||
userId: CharSequence? = null,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey.openPGPKey, evaluationDate)
|
||||
val signingPrivKey: OpenPGPPrivateKey = signingKey.unlock(signingKeyProtector)
|
||||
val hashAlgorithms =
|
||||
if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId)
|
||||
else keyRingInfo.getPreferredHashAlgorithms(signingPubKey.keyIdentifier)
|
||||
else keyRingInfo.getPreferredHashAlgorithms(signingKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm = negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(
|
||||
signingKey, signingSubkey, hashAlgorithm, signatureType, true, subpacketCallback)
|
||||
}
|
||||
addSigningMethod(signingPrivKey, hashAlgorithm, signatureType, true, subpacketCallback)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,65 +414,44 @@ class SigningOptions {
|
|||
*/
|
||||
@Throws(KeyException::class, PGPException::class)
|
||||
@JvmOverloads
|
||||
@Deprecated("Pass an OpenPGPSecretKey instead.")
|
||||
fun addDetachedSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: PGPSecretKeyRing,
|
||||
keyId: Long,
|
||||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(of(signingKey))
|
||||
}
|
||||
|
||||
for (signingPubKey in signingPubKeys) {
|
||||
if (signingPubKey.keyIdentifier.matches(KeyIdentifier(keyId))) {
|
||||
val signingSecKey: PGPSecretKey =
|
||||
signingKey.getSecretKey(signingPubKey.keyIdentifier)
|
||||
?: throw MissingSecretKeyException(
|
||||
of(signingKey), signingPubKey.keyIdentifier.keyId)
|
||||
val signingSubkey: PGPPrivateKey = signingSecKey.unlock(signingKeyProtector)
|
||||
val hashAlgorithms =
|
||||
keyRingInfo.getPreferredHashAlgorithms(signingPubKey.keyIdentifier)
|
||||
val hashAlgorithm: HashAlgorithm =
|
||||
negotiateHashAlgorithm(hashAlgorithms, getPolicy())
|
||||
addSigningMethod(
|
||||
signingKey,
|
||||
signingSubkey,
|
||||
hashAlgorithm,
|
||||
) =
|
||||
addDetachedSignature(
|
||||
signingKeyProtector,
|
||||
signingKey.toOpenPGPKey().getSecretKey(KeyIdentifier(keyId))
|
||||
?: throw MissingSecretKeyException(of(signingKey), keyId),
|
||||
null,
|
||||
signatureType,
|
||||
true,
|
||||
subpacketsCallback)
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
throw MissingSecretKeyException(of(signingKey), keyId)
|
||||
}
|
||||
|
||||
private fun addSigningMethod(
|
||||
signingKey: PGPSecretKeyRing,
|
||||
signingSubkey: PGPPrivateKey,
|
||||
signingKey: OpenPGPPrivateKey,
|
||||
hashAlgorithm: HashAlgorithm,
|
||||
signatureType: DocumentSignatureType,
|
||||
detached: Boolean,
|
||||
subpacketCallback: Callback? = null
|
||||
) {
|
||||
val signingKeyIdentifier = SubkeyIdentifier(signingKey, signingSubkey.keyID)
|
||||
val signingSecretKey: PGPSecretKey = signingKey.getSecretKey(signingSubkey.keyID)
|
||||
val signingSecretKey: PGPSecretKey = signingKey.secretKey.pgpSecretKey
|
||||
val publicKeyAlgorithm = requireFromId(signingSecretKey.publicKey.algorithm)
|
||||
val bitStrength = signingSecretKey.publicKey.bitStrength
|
||||
if (!getPolicy().publicKeyAlgorithmPolicy.isAcceptable(publicKeyAlgorithm, bitStrength)) {
|
||||
throw UnacceptableSigningKeyException(
|
||||
PublicKeyAlgorithmPolicyException(
|
||||
of(signingKey), signingSecretKey.keyID, publicKeyAlgorithm, bitStrength))
|
||||
of(signingKey.secretKey.pgpSecretKey),
|
||||
signingSecretKey.keyID,
|
||||
publicKeyAlgorithm,
|
||||
bitStrength))
|
||||
}
|
||||
|
||||
val generator: PGPSignatureGenerator =
|
||||
createSignatureGenerator(signingSubkey, hashAlgorithm, signatureType)
|
||||
createSignatureGenerator(
|
||||
signingKey.unlockedKey.privateKey, hashAlgorithm, signatureType)
|
||||
|
||||
// Subpackets
|
||||
val hashedSubpackets =
|
||||
|
@ -405,7 +467,7 @@ class SigningOptions {
|
|||
val signingMethod =
|
||||
if (detached) SigningMethod.detachedSignature(generator, hashAlgorithm)
|
||||
else SigningMethod.inlineSignature(generator, hashAlgorithm)
|
||||
(signingMethods as MutableMap)[signingKeyIdentifier] = signingMethod
|
||||
(signingMethods as MutableMap)[signingKey] = signingMethod
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.bouncycastle.bcpg.KeyIdentifier
|
|||
import org.bouncycastle.openpgp.PGPKeyRing
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
|
||||
|
||||
/**
|
||||
* Tuple class used to identify a subkey by fingerprints of the primary key of the subkeys key ring,
|
||||
|
@ -32,6 +33,8 @@ class SubkeyIdentifier(
|
|||
OpenPgpFingerprint.of(key.certificate.pgpPublicKeyRing),
|
||||
OpenPgpFingerprint.of(key.pgpPublicKey))
|
||||
|
||||
constructor(key: OpenPGPPrivateKey) : this(key.secretKey)
|
||||
|
||||
constructor(
|
||||
keys: PGPKeyRing,
|
||||
subkeyFingerprint: OpenPgpFingerprint
|
||||
|
|
|
@ -10,6 +10,8 @@ import openpgp.openPgpKeyId
|
|||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey
|
||||
import org.bouncycastle.openpgp.PGPSecretKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.bouncycastle.extensions.isEncrypted
|
||||
|
@ -35,6 +37,36 @@ class UnlockSecretKey {
|
|||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(PGPException::class)
|
||||
fun unlockSecretKey(
|
||||
secretKey: OpenPGPSecretKey,
|
||||
protector: SecretKeyRingProtector
|
||||
): OpenPGPPrivateKey {
|
||||
val privateKey =
|
||||
try {
|
||||
secretKey.unlock(protector)
|
||||
} catch (e: PGPException) {
|
||||
throw WrongPassphraseException(secretKey.keyIdentifier, e)
|
||||
}
|
||||
|
||||
if (privateKey == null) {
|
||||
if (secretKey.pgpSecretKey.s2K.type in 100..110) {
|
||||
throw PGPException(
|
||||
"Cannot decrypt secret key ${secretKey.keyIdentifier}: \n" +
|
||||
"Unsupported private S2K type ${secretKey.pgpSecretKey.s2K.type}")
|
||||
}
|
||||
throw PGPException("Cannot decrypt secret key.")
|
||||
}
|
||||
|
||||
if (PGPainless.getPolicy().isEnableKeyParameterValidation()) {
|
||||
PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(
|
||||
privateKey.unlockedKey.privateKey, privateKey.unlockedKey.publicKey)
|
||||
}
|
||||
|
||||
return privateKey
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(PGPException::class)
|
||||
fun unlockSecretKey(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue