mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 10:19:39 +02:00
Port SecretKeyRingEditor, replace Singleton usage with API instance calls
This commit is contained in:
parent
2a71a98bba
commit
57540d8028
43 changed files with 811 additions and 611 deletions
|
@ -67,9 +67,14 @@ class PGPainless(
|
|||
* @param referenceTime reference time for evaluation
|
||||
* @return [KeyRingInfo] wrapper
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun inspect(keyOrCertificate: OpenPGPCertificate, referenceTime: Date = Date()): KeyRingInfo =
|
||||
KeyRingInfo(keyOrCertificate, this, referenceTime)
|
||||
|
||||
@JvmOverloads
|
||||
fun modify(key: OpenPGPKey, referenceTime: Date = Date()): SecretKeyRingEditor =
|
||||
SecretKeyRingEditor(key, this, referenceTime)
|
||||
|
||||
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()
|
||||
|
||||
fun toKey(secretKeyRing: PGPSecretKeyRing): OpenPGPKey =
|
||||
|
|
|
@ -694,7 +694,7 @@ class OpenPgpMessageInputStream(
|
|||
private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): OpenPGPKey? =
|
||||
options.getDecryptionKeys().firstOrNull {
|
||||
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
|
||||
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey ->
|
||||
api.inspect(it).decryptionSubkeys.any { subkey ->
|
||||
pkesk.keyIdentifier.matches(subkey.keyIdentifier)
|
||||
}
|
||||
}
|
||||
|
@ -702,7 +702,7 @@ class OpenPgpMessageInputStream(
|
|||
private fun getDecryptionKeys(pkesk: PGPPublicKeyEncryptedData): List<OpenPGPKey> =
|
||||
options.getDecryptionKeys().filter {
|
||||
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
|
||||
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey ->
|
||||
api.inspect(it).decryptionSubkeys.any { subkey ->
|
||||
pkesk.keyIdentifier.matches(subkey.keyIdentifier)
|
||||
}
|
||||
}
|
||||
|
@ -713,7 +713,7 @@ class OpenPgpMessageInputStream(
|
|||
val algorithm = pkesk.algorithm
|
||||
val candidates = mutableListOf<OpenPGPSecretKey>()
|
||||
options.getDecryptionKeys().forEach {
|
||||
val info = PGPainless.inspectKeyRing(it)
|
||||
val info = api.inspect(it)
|
||||
for (key in info.decryptionSubkeys) {
|
||||
if (key.pgpPublicKey.algorithm == algorithm &&
|
||||
info.isSecretKeyAvailable(key.keyIdentifier)) {
|
||||
|
|
|
@ -10,7 +10,6 @@ import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
|||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.PGPainless.Companion.inspectKeyRing
|
||||
import org.pgpainless.algorithm.EncryptionPurpose
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||
import org.pgpainless.algorithm.negotiation.SymmetricKeyAlgorithmNegotiator.Companion.byPopularity
|
||||
|
@ -191,7 +190,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
|
|||
userId: CharSequence,
|
||||
encryptionKeySelector: EncryptionKeySelector
|
||||
) = apply {
|
||||
val info = inspectKeyRing(cert, evaluationDate)
|
||||
val info = api.inspect(cert, evaluationDate)
|
||||
val subkeys =
|
||||
encryptionKeySelector.selectEncryptionSubkeys(
|
||||
info.getEncryptionSubkeys(userId, purpose))
|
||||
|
@ -289,7 +288,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
|
|||
selector: EncryptionKeySelector,
|
||||
wildcardKeyId: Boolean
|
||||
) = apply {
|
||||
val info = inspectKeyRing(cert, evaluationDate)
|
||||
val info = api.inspect(cert, evaluationDate)
|
||||
val primaryKeyExpiration =
|
||||
try {
|
||||
info.primaryKeyExpirationDate
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.*
|
|||
import org.bouncycastle.openpgp.PGPLiteralData
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||
import org.pgpainless.algorithm.StreamEncoding
|
||||
import org.pgpainless.algorithm.SymmetricKeyAlgorithm
|
||||
|
@ -34,6 +35,9 @@ data class EncryptionResult(
|
|||
val isForYourEyesOnly: Boolean
|
||||
get() = PGPLiteralData.CONSOLE == fileName
|
||||
|
||||
fun isEncryptedFor(certificate: OpenPGPCertificate) =
|
||||
recipients.any { certificate.getKey(it.keyIdentifier) != null }
|
||||
|
||||
/**
|
||||
* Returns true, if the message was encrypted for at least one subkey of the given certificate.
|
||||
*
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKey
|
|||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.PGPainless.Companion.inspectKeyRing
|
||||
import org.pgpainless.algorithm.DocumentSignatureType
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
import org.pgpainless.algorithm.PublicKeyAlgorithm.Companion.requireFromId
|
||||
|
@ -138,6 +137,7 @@ class SigningOptions(private val api: PGPainless) {
|
|||
signatureType: DocumentSignatureType
|
||||
) = addInlineSignature(signingKeyProtector, api.toKey(signingKey), signatureType)
|
||||
|
||||
@JvmOverloads
|
||||
fun addInlineSignature(
|
||||
signingKeyProtector: SecretKeyRingProtector,
|
||||
signingKey: OpenPGPKey,
|
||||
|
@ -145,7 +145,7 @@ class SigningOptions(private val api: PGPainless) {
|
|||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketsCallback: Callback? = null
|
||||
) = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
val keyRingInfo = api.inspect(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey),
|
||||
|
@ -212,7 +212,7 @@ class SigningOptions(private val api: PGPainless) {
|
|||
subpacketsCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val openPGPKey = signingKey.openPGPKey
|
||||
val keyRingInfo = inspectKeyRing(openPGPKey, evaluationDate)
|
||||
val keyRingInfo = api.inspect(openPGPKey, evaluationDate)
|
||||
val signingPubKeys = keyRingInfo.signingSubkeys
|
||||
if (signingPubKeys.isEmpty()) {
|
||||
throw UnacceptableSigningKeyException(openPGPKey)
|
||||
|
@ -319,7 +319,7 @@ class SigningOptions(private val api: PGPainless) {
|
|||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate)
|
||||
val keyRingInfo = api.inspect(signingKey, evaluationDate)
|
||||
if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
|
||||
throw UnboundUserIdException(
|
||||
of(signingKey),
|
||||
|
@ -380,7 +380,7 @@ class SigningOptions(private val api: PGPainless) {
|
|||
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
|
||||
subpacketCallback: Callback? = null
|
||||
): SigningOptions = apply {
|
||||
val keyRingInfo = inspectKeyRing(signingKey.openPGPKey, evaluationDate)
|
||||
val keyRingInfo = api.inspect(signingKey.openPGPKey, evaluationDate)
|
||||
val signingPrivKey: OpenPGPPrivateKey = signingKey.unlock(signingKeyProtector)
|
||||
val hashAlgorithms =
|
||||
if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId)
|
||||
|
|
|
@ -134,7 +134,7 @@ class CertifyCertificate(private val api: PGPainless) {
|
|||
key: OpenPGPKey,
|
||||
protector: SecretKeyRingProtector
|
||||
): CertificationOnUserIdWithSubpackets {
|
||||
val secretKey = getCertifyingSecretKey(key)
|
||||
val secretKey = getCertifyingSecretKey(key, api)
|
||||
val sigBuilder =
|
||||
ThirdPartyCertificationSignatureBuilder(
|
||||
certificationType.asSignatureType(), secretKey, protector, api)
|
||||
|
@ -220,7 +220,7 @@ class CertifyCertificate(private val api: PGPainless) {
|
|||
key: OpenPGPKey,
|
||||
protector: SecretKeyRingProtector
|
||||
): DelegationOnCertificateWithSubpackets {
|
||||
val secretKey = getCertifyingSecretKey(key)
|
||||
val secretKey = getCertifyingSecretKey(key, api)
|
||||
val sigBuilder = ThirdPartyDirectKeySignatureBuilder(secretKey, protector, api)
|
||||
if (trustworthiness != null) {
|
||||
sigBuilder.hashedSubpackets.setTrust(
|
||||
|
@ -306,10 +306,11 @@ class CertifyCertificate(private val api: PGPainless) {
|
|||
companion object {
|
||||
@JvmStatic
|
||||
private fun getCertifyingSecretKey(
|
||||
certificationKey: OpenPGPKey
|
||||
certificationKey: OpenPGPKey,
|
||||
api: PGPainless
|
||||
): OpenPGPKey.OpenPGPSecretKey {
|
||||
val now = Date()
|
||||
val info = PGPainless.inspectKeyRing(certificationKey, now)
|
||||
val info = api.inspect(certificationKey, now)
|
||||
|
||||
val fingerprint = info.fingerprint
|
||||
val certificationPubKey = info.getPublicKey(fingerprint)
|
||||
|
|
|
@ -8,10 +8,11 @@ import java.util.*
|
|||
import java.util.function.Predicate
|
||||
import javax.annotation.Nonnull
|
||||
import kotlin.NoSuchElementException
|
||||
import openpgp.openPgpKeyId
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.bcpg.sig.KeyExpirationTime
|
||||
import org.bouncycastle.openpgp.*
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPSubkey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
|
@ -20,7 +21,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKeyEditor
|
|||
import org.bouncycastle.openpgp.api.OpenPGPSignature
|
||||
import org.bouncycastle.openpgp.api.SignatureParameters
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.PGPainless.Companion.inspectKeyRing
|
||||
import org.pgpainless.algorithm.AlgorithmSuite
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
||||
|
@ -29,7 +29,6 @@ import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator
|
|||
import org.pgpainless.bouncycastle.extensions.checksumCalculator
|
||||
import org.pgpainless.bouncycastle.extensions.getKeyExpirationDate
|
||||
import org.pgpainless.bouncycastle.extensions.publicKeyAlgorithm
|
||||
import org.pgpainless.bouncycastle.extensions.requirePublicKey
|
||||
import org.pgpainless.key.OpenPgpFingerprint
|
||||
import org.pgpainless.key.generation.KeyRingBuilder
|
||||
import org.pgpainless.key.generation.KeySpec
|
||||
|
@ -50,8 +49,6 @@ class SecretKeyRingEditor(
|
|||
override val referenceTime: Date = Date()
|
||||
) : SecretKeyRingEditorInterface {
|
||||
|
||||
private var secretKeyRing: PGPSecretKeyRing = key.pgpSecretKeyRing
|
||||
|
||||
@JvmOverloads
|
||||
constructor(
|
||||
secretKeyRing: PGPSecretKeyRing,
|
||||
|
@ -64,8 +61,7 @@ class SecretKeyRingEditor(
|
|||
callback: SelfSignatureSubpackets.Callback?,
|
||||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface {
|
||||
key = PGPainless.getInstance().toKey(secretKeyRing)
|
||||
val info = inspectKeyRing(key, referenceTime)
|
||||
val info = api.inspect(key, referenceTime)
|
||||
require(!info.isHardRevoked(userId)) {
|
||||
"User-ID $userId is hard revoked and cannot be re-certified."
|
||||
}
|
||||
|
@ -89,7 +85,7 @@ class SecretKeyRingEditor(
|
|||
.setSignatureCreationTime(referenceTime)
|
||||
.setHashedSubpacketsFunction { subpacketGenerator ->
|
||||
val subpackets = SignatureSubpackets(subpacketGenerator)
|
||||
subpackets.setAppropriateIssuerInfo(secretKeyRing.publicKey)
|
||||
subpackets.setAppropriateIssuerInfo(key.primaryKey.pgpPublicKey)
|
||||
|
||||
subpackets.setKeyFlags(info.getKeyFlagsOf(key.keyIdentifier))
|
||||
subpackets.setPreferredHashAlgorithms(hashAlgorithmPreferences)
|
||||
|
@ -111,7 +107,6 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
})
|
||||
.done()
|
||||
secretKeyRing = key.pgpSecretKeyRing
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -120,8 +115,8 @@ class SecretKeyRingEditor(
|
|||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface {
|
||||
val uid = sanitizeUserId(userId)
|
||||
val primaryKey = secretKeyRing.publicKey
|
||||
var info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
val primaryKey = key.primaryKey.pgpPublicKey
|
||||
var info = api.inspect(key, referenceTime)
|
||||
val primaryUserId = info.primaryUserId
|
||||
val signature =
|
||||
if (primaryUserId == null) info.latestDirectKeySelfSignature
|
||||
|
@ -144,7 +139,7 @@ class SecretKeyRingEditor(
|
|||
protector)
|
||||
|
||||
// unmark previous primary user-ids to be non-primary
|
||||
info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
info = api.inspect(key, referenceTime)
|
||||
info.validAndExpiredUserIds
|
||||
.filterNot { it == uid }
|
||||
.forEach { otherUserId ->
|
||||
|
@ -215,7 +210,7 @@ class SecretKeyRingEditor(
|
|||
require(oldUID.isNotBlank()) { "Old user-ID cannot be empty." }
|
||||
require(newUID.isNotBlank()) { "New user-ID cannot be empty." }
|
||||
|
||||
val info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
val info = api.inspect(key, referenceTime)
|
||||
if (!info.isUserIdValid(oldUID)) {
|
||||
throw NoSuchElementException(
|
||||
"Key does not carry user-ID '$oldUID', or it is not valid.")
|
||||
|
@ -244,7 +239,6 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
},
|
||||
protector)
|
||||
|
||||
return revokeUserId(oldUID, protector)
|
||||
}
|
||||
|
||||
|
@ -270,7 +264,7 @@ class SecretKeyRingEditor(
|
|||
callback: SelfSignatureSubpackets.Callback?,
|
||||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface {
|
||||
val version = OpenPGPKeyVersion.from(secretKeyRing.publicKey.version)
|
||||
val version = OpenPGPKeyVersion.from(key.primarySecretKey.version)
|
||||
val keyPair = KeyRingBuilder.generateKeyPair(keySpec, version, api.implementation)
|
||||
val subkeyProtector =
|
||||
PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyIdentifier, subkeyPassphrase)
|
||||
|
@ -303,8 +297,8 @@ class SecretKeyRingEditor(
|
|||
"Public key algorithm policy violation: $subkeyAlgorithm with bit strength $bitStrength is not acceptable."
|
||||
}
|
||||
|
||||
val primaryKey = secretKeyRing.secretKey
|
||||
val info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
val primaryKey = key.primarySecretKey.pgpSecretKey
|
||||
val info = api.inspect(key, referenceTime)
|
||||
val hashAlgorithm =
|
||||
HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(api.algorithmPolicy)
|
||||
.negotiateHashAlgorithm(info.preferredHashAlgorithms)
|
||||
|
@ -341,7 +335,8 @@ class SecretKeyRingEditor(
|
|||
secretSubkey =
|
||||
KeyRingUtils.secretKeyPlusSignature(
|
||||
secretSubkey, skBindingBuilder.build(secretSubkey.publicKey))
|
||||
secretKeyRing = KeyRingUtils.keysPlusSecretKey(secretKeyRing, secretSubkey)
|
||||
val secretKeyRing = KeyRingUtils.keysPlusSecretKey(key.pgpSecretKeyRing, secretSubkey)
|
||||
key = api.toKey(secretKeyRing)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -356,26 +351,33 @@ class SecretKeyRingEditor(
|
|||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): SecretKeyRingEditorInterface {
|
||||
return revokeSubKey(secretKeyRing.secretKey.keyID, protector, callback)
|
||||
return revokeSubKey(key.keyIdentifier, protector, callback)
|
||||
}
|
||||
|
||||
override fun revokeSubKey(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): SecretKeyRingEditorInterface {
|
||||
return revokeSubKey(
|
||||
subkeyId, protector, callbackFromRevocationAttributes(revocationAttributes))
|
||||
subkeyIdentifier, protector, callbackFromRevocationAttributes(revocationAttributes))
|
||||
}
|
||||
|
||||
override fun revokeSubKey(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): SecretKeyRingEditorInterface {
|
||||
val revokeeSubKey = secretKeyRing.requirePublicKey(subkeyId)
|
||||
var secretKeyRing = key.pgpSecretKeyRing
|
||||
val revokeeSubKey =
|
||||
key.getKey(subkeyIdentifier)
|
||||
?: throw NoSuchElementException(
|
||||
"Certificate ${key.keyIdentifier} does not contain subkey $subkeyIdentifier")
|
||||
val subkeyRevocation = generateRevocation(protector, revokeeSubKey, callback)
|
||||
secretKeyRing = injectCertification(secretKeyRing, revokeeSubKey, subkeyRevocation)
|
||||
secretKeyRing =
|
||||
injectCertification(
|
||||
secretKeyRing, revokeeSubKey.pgpPublicKey, subkeyRevocation.signature)
|
||||
key = api.toKey(secretKeyRing)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -451,6 +453,7 @@ class SecretKeyRingEditor(
|
|||
expiration: Date?,
|
||||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface {
|
||||
var secretKeyRing = key.pgpSecretKeyRing
|
||||
require(secretKeyRing.secretKey.isMasterKey) {
|
||||
"OpenPGP key does not appear to contain a primary secret key."
|
||||
}
|
||||
|
@ -465,8 +468,9 @@ class SecretKeyRingEditor(
|
|||
reissueDirectKeySignature(expiration, protector, prevDirectKeySig).signature)
|
||||
}
|
||||
|
||||
val primaryUserId =
|
||||
inspectKeyRing(secretKeyRing, referenceTime).getPossiblyExpiredPrimaryUserId()
|
||||
val info = api.inspect(key, referenceTime)
|
||||
|
||||
val primaryUserId = info.getPossiblyExpiredPrimaryUserId()
|
||||
if (primaryUserId != null) {
|
||||
val prevUserIdSig = getPreviousUserIdSignatures(primaryUserId)
|
||||
val userIdSig =
|
||||
|
@ -474,7 +478,6 @@ class SecretKeyRingEditor(
|
|||
secretKeyRing = injectCertification(secretKeyRing, primaryUserId, userIdSig)
|
||||
}
|
||||
|
||||
val info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
for (userId in info.validUserIds) {
|
||||
if (userId == primaryUserId) {
|
||||
continue
|
||||
|
@ -493,35 +496,40 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
}
|
||||
|
||||
key = api.toKey(secretKeyRing)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setExpirationDateOfSubkey(
|
||||
expiration: Date?,
|
||||
keyId: Long,
|
||||
keyId: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface = apply {
|
||||
var secretKeyRing = key.pgpSecretKeyRing
|
||||
|
||||
// is primary key
|
||||
if (keyId == secretKeyRing.publicKey.keyID) {
|
||||
if (keyId.matches(key.keyIdentifier)) {
|
||||
return setExpirationDate(expiration, protector)
|
||||
}
|
||||
|
||||
// is subkey
|
||||
val subkey =
|
||||
secretKeyRing.getPublicKey(keyId)
|
||||
?: throw NoSuchElementException("No subkey with ID ${keyId.openPgpKeyId()} found.")
|
||||
key.getKey(keyId) ?: throw NoSuchElementException("No subkey with ID $keyId found.")
|
||||
val prevBinding =
|
||||
inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId)
|
||||
api.inspect(key).getCurrentSubkeyBindingSignature(keyId)
|
||||
?: throw NoSuchElementException(
|
||||
"Previous subkey binding signaure for ${keyId.openPgpKeyId()} MUST NOT be null.")
|
||||
"Previous subkey binding signaure for $keyId MUST NOT be null.")
|
||||
val bindingSig = reissueSubkeyBindingSignature(subkey, expiration, protector, prevBinding)
|
||||
secretKeyRing = injectCertification(secretKeyRing, subkey, bindingSig)
|
||||
secretKeyRing =
|
||||
injectCertification(secretKeyRing, subkey.pgpPublicKey, bindingSig.signature)
|
||||
|
||||
key = api.toKey(secretKeyRing)
|
||||
}
|
||||
|
||||
override fun createMinimalRevocationCertificate(
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPPublicKeyRing {
|
||||
): OpenPGPCertificate {
|
||||
// Check reason
|
||||
if (revocationAttributes != null) {
|
||||
require(RevocationAttributes.Reason.isKeyRevocation(revocationAttributes.reason)) {
|
||||
|
@ -530,49 +538,47 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
|
||||
val revocation = createRevocation(protector, revocationAttributes)
|
||||
var primaryKey = secretKeyRing.secretKey.publicKey
|
||||
var primaryKey = key.primaryKey.pgpPublicKey
|
||||
primaryKey = KeyRingUtils.getStrippedDownPublicKey(primaryKey)
|
||||
primaryKey = PGPPublicKey.addCertification(primaryKey, revocation)
|
||||
return PGPPublicKeyRing(listOf(primaryKey))
|
||||
primaryKey = PGPPublicKey.addCertification(primaryKey, revocation.signature)
|
||||
return api.toCertificate(PGPPublicKeyRing(listOf(primaryKey)))
|
||||
}
|
||||
|
||||
override fun createRevocation(
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature {
|
||||
): OpenPGPSignature {
|
||||
return generateRevocation(
|
||||
protector,
|
||||
secretKeyRing.publicKey,
|
||||
callbackFromRevocationAttributes(revocationAttributes))
|
||||
protector, key.primaryKey, callbackFromRevocationAttributes(revocationAttributes))
|
||||
}
|
||||
|
||||
override fun createRevocation(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature {
|
||||
): OpenPGPSignature {
|
||||
return generateRevocation(
|
||||
protector,
|
||||
secretKeyRing.requirePublicKey(subkeyId),
|
||||
key.getKey(subkeyIdentifier),
|
||||
callbackFromRevocationAttributes(revocationAttributes))
|
||||
}
|
||||
|
||||
override fun createRevocation(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): PGPSignature {
|
||||
return generateRevocation(protector, secretKeyRing.requirePublicKey(subkeyId), callback)
|
||||
): OpenPGPSignature {
|
||||
return generateRevocation(protector, key.getKey(subkeyIdentifier), callback)
|
||||
}
|
||||
|
||||
override fun createRevocation(
|
||||
subkeyFingerprint: OpenPgpFingerprint,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature {
|
||||
): OpenPGPSignature {
|
||||
return generateRevocation(
|
||||
protector,
|
||||
secretKeyRing.requirePublicKey(subkeyFingerprint),
|
||||
key.getKey(subkeyFingerprint.keyIdentifier),
|
||||
callbackFromRevocationAttributes(revocationAttributes))
|
||||
}
|
||||
|
||||
|
@ -599,8 +605,8 @@ class SecretKeyRingEditor(
|
|||
mapOf(keyIdentifier to oldPassphrase), oldProtectionSettings, null))
|
||||
}
|
||||
|
||||
override fun done(): PGPSecretKeyRing {
|
||||
return secretKeyRing
|
||||
override fun done(): OpenPGPKey {
|
||||
return key
|
||||
}
|
||||
|
||||
private fun sanitizeUserId(userId: CharSequence): CharSequence =
|
||||
|
@ -619,11 +625,11 @@ class SecretKeyRingEditor(
|
|||
|
||||
private fun generateRevocation(
|
||||
protector: SecretKeyRingProtector,
|
||||
revokeeSubkey: PGPPublicKey,
|
||||
revokeeSubkey: OpenPGPComponentKey,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): PGPSignature {
|
||||
): OpenPGPSignature {
|
||||
val signatureType =
|
||||
if (revokeeSubkey.isMasterKey) SignatureType.KEY_REVOCATION
|
||||
if (revokeeSubkey.isPrimaryKey) SignatureType.KEY_REVOCATION
|
||||
else SignatureType.SUBKEY_REVOCATION
|
||||
|
||||
return RevocationSignatureBuilder(signatureType, key.primarySecretKey, protector, api)
|
||||
|
@ -643,19 +649,20 @@ class SecretKeyRingEditor(
|
|||
applyCallback(callback)
|
||||
}
|
||||
.let {
|
||||
secretKeyRing =
|
||||
injectCertification(secretKeyRing, userId, it.build(userId.toString()))
|
||||
val secretKeyRing =
|
||||
injectCertification(key.pgpSecretKeyRing, userId, it.build(userId.toString()))
|
||||
key = api.toKey(secretKeyRing)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getPreviousDirectKeySignature(): PGPSignature? {
|
||||
val info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
val info = api.inspect(key, referenceTime)
|
||||
return info.latestDirectKeySelfSignature
|
||||
}
|
||||
|
||||
private fun getPreviousUserIdSignatures(userId: String): PGPSignature? {
|
||||
val info = inspectKeyRing(secretKeyRing, referenceTime)
|
||||
val info = api.inspect(key, referenceTime)
|
||||
return info.getLatestUserIdCertification(userId)
|
||||
}
|
||||
|
||||
|
@ -696,7 +703,7 @@ class SecretKeyRingEditor(
|
|||
) {
|
||||
if (expiration != null) {
|
||||
hashedSubpackets.setKeyExpirationTime(
|
||||
true, secretKeyRing.publicKey.creationTime, expiration)
|
||||
true, key.primaryKey.creationTime, expiration)
|
||||
} else {
|
||||
hashedSubpackets.setKeyExpirationTime(KeyExpirationTime(true, 0))
|
||||
}
|
||||
|
@ -713,6 +720,7 @@ class SecretKeyRingEditor(
|
|||
secretKeyRingProtector: SecretKeyRingProtector,
|
||||
prevDirectKeySig: PGPSignature
|
||||
): OpenPGPSignature {
|
||||
val secretKeyRing = key.pgpSecretKeyRing
|
||||
return DirectKeySelfSignatureBuilder(
|
||||
secretKeyRing, secretKeyRingProtector, prevDirectKeySig, api)
|
||||
.apply {
|
||||
|
@ -735,13 +743,13 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
|
||||
private fun reissueSubkeyBindingSignature(
|
||||
subkey: PGPPublicKey,
|
||||
subkey: OpenPGPComponentKey,
|
||||
expiration: Date?,
|
||||
protector: SecretKeyRingProtector,
|
||||
prevSubkeyBindingSignature: PGPSignature
|
||||
): PGPSignature {
|
||||
val primaryKey = secretKeyRing.publicKey
|
||||
val secretSubkey: PGPSecretKey? = secretKeyRing.getSecretKey(subkey.keyID)
|
||||
): OpenPGPSignature {
|
||||
val primaryKey = key.primaryKey
|
||||
val secretSubkey: OpenPGPSecretKey? = key.getSecretKey(subkey)
|
||||
|
||||
val builder =
|
||||
SubkeyBindingSignatureBuilder(
|
||||
|
@ -749,7 +757,7 @@ class SecretKeyRingEditor(
|
|||
builder.hashedSubpackets.apply {
|
||||
// set expiration
|
||||
setSignatureCreationTime(referenceTime)
|
||||
setKeyExpirationTime(subkey, expiration)
|
||||
setKeyExpirationTime(subkey.pgpPublicKey, expiration)
|
||||
setSignatureExpirationTime(null) // avoid copying sig exp time
|
||||
|
||||
// signing-capable subkeys need embedded primary key binding sig
|
||||
|
@ -758,7 +766,7 @@ class SecretKeyRingEditor(
|
|||
if (secretSubkey == null) {
|
||||
throw NoSuchElementException(
|
||||
"Secret key does not contain secret-key" +
|
||||
" component for subkey ${subkey.keyID.openPgpKeyId()}")
|
||||
" component for subkey ${subkey.keyIdentifier}")
|
||||
}
|
||||
|
||||
// create new embedded back-sig
|
||||
|
@ -766,7 +774,8 @@ class SecretKeyRingEditor(
|
|||
addEmbeddedSignature(
|
||||
PrimaryKeyBindingSignatureBuilder(
|
||||
key.getSecretKey(subkey.keyIdentifier), protector, api)
|
||||
.build(primaryKey))
|
||||
.build(primaryKey)
|
||||
.signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -775,7 +784,7 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
|
||||
private fun selectUserIds(predicate: Predicate<String>): List<String> =
|
||||
inspectKeyRing(secretKeyRing).validUserIds.filter { predicate.test(it) }
|
||||
key.validUserIds.map { it.userId }.filter { predicate.test(it) }.toList()
|
||||
|
||||
private class WithKeyRingEncryptionSettingsImpl(
|
||||
private val editor: SecretKeyRingEditor,
|
||||
|
@ -805,15 +814,17 @@ class SecretKeyRingEditor(
|
|||
val protector =
|
||||
PasswordBasedSecretKeyRingProtector(
|
||||
newProtectionSettings, SolitaryPassphraseProvider(passphrase))
|
||||
val secretKeys = changePassphrase(keyId, editor.secretKeyRing, oldProtector, protector)
|
||||
editor.secretKeyRing = secretKeys
|
||||
val secretKeys =
|
||||
changePassphrase(keyId, editor.key.pgpSecretKeyRing, oldProtector, protector)
|
||||
editor.key = editor.api.toKey(secretKeys)
|
||||
return editor
|
||||
}
|
||||
|
||||
override fun toNoPassphrase(): SecretKeyRingEditorInterface {
|
||||
val protector = UnprotectedKeysProtector()
|
||||
val secretKeys = changePassphrase(keyId, editor.secretKeyRing, oldProtector, protector)
|
||||
editor.secretKeyRing = secretKeys
|
||||
val secretKeys =
|
||||
changePassphrase(keyId, editor.key.pgpSecretKeyRing, oldProtector, protector)
|
||||
editor.key = editor.api.toKey(secretKeys)
|
||||
return editor
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@ import java.security.NoSuchAlgorithmException
|
|||
import java.util.*
|
||||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.openpgp.*
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.key.OpenPgpFingerprint
|
||||
import org.pgpainless.key.generation.KeySpec
|
||||
|
@ -262,26 +265,37 @@ interface SecretKeyRingEditorInterface {
|
|||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes? = null
|
||||
): SecretKeyRingEditorInterface =
|
||||
revokeSubKey(fingerprint.keyId, protector, revocationAttributes)
|
||||
revokeSubKey(fingerprint.keyIdentifier, protector, revocationAttributes)
|
||||
|
||||
@Deprecated("Pass in a KeyIdentifier instead of keyId")
|
||||
fun revokeSubKey(subkeyId: Long, protector: SecretKeyRingProtector) =
|
||||
revokeSubKey(KeyIdentifier(subkeyId), protector)
|
||||
|
||||
/**
|
||||
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
|
||||
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
|
||||
*
|
||||
* @param subkeyId id of the subkey
|
||||
* @param subkeyIdentifier id of the subkey
|
||||
* @param protector protector to unlock the primary key
|
||||
* @return the builder
|
||||
* @throws PGPException in case we cannot generate a revocation signature for the subkey
|
||||
*/
|
||||
@Throws(PGPException::class)
|
||||
fun revokeSubKey(subkeyId: Long, protector: SecretKeyRingProtector) =
|
||||
revokeSubKey(subkeyId, protector, null as RevocationAttributes?)
|
||||
fun revokeSubKey(subkeyIdentifier: KeyIdentifier, protector: SecretKeyRingProtector) =
|
||||
revokeSubKey(subkeyIdentifier, protector, null as RevocationAttributes?)
|
||||
|
||||
@Deprecated("Pass in a KeyIdentifier instead of keyId")
|
||||
fun revokeSubKey(
|
||||
subkeyId: Long,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes? = null
|
||||
) = revokeSubKey(KeyIdentifier(subkeyId), protector, revocationAttributes)
|
||||
|
||||
/**
|
||||
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
|
||||
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
|
||||
*
|
||||
* @param subkeyId id of the subkey
|
||||
* @param subkeyIdentifier id of the subkey
|
||||
* @param protector protector to unlock the primary key
|
||||
* @param revocationAttributes reason for the revocation
|
||||
* @return the builder
|
||||
|
@ -289,18 +303,25 @@ interface SecretKeyRingEditorInterface {
|
|||
*/
|
||||
@Throws(PGPException::class)
|
||||
fun revokeSubKey(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes? = null
|
||||
): SecretKeyRingEditorInterface
|
||||
|
||||
@Deprecated("Pass in a KeyIdentifier instead of keyId.")
|
||||
fun revokeSubKey(
|
||||
keyId: Long,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
) = revokeSubKey(KeyIdentifier(keyId), protector, callback)
|
||||
|
||||
/**
|
||||
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
|
||||
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
|
||||
*
|
||||
* The provided subpackets callback is used to modify the revocation signatures subpackets.
|
||||
*
|
||||
* @param subkeyId id of the subkey
|
||||
* @param subkeyIdentifier id of the subkey
|
||||
* @param protector protector to unlock the secret key ring
|
||||
* @param callback callback which can be used to modify the subpackets of the revocation
|
||||
* signature
|
||||
|
@ -309,7 +330,7 @@ interface SecretKeyRingEditorInterface {
|
|||
*/
|
||||
@Throws(PGPException::class)
|
||||
fun revokeSubKey(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): SecretKeyRingEditorInterface
|
||||
|
@ -470,6 +491,14 @@ interface SecretKeyRingEditorInterface {
|
|||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface
|
||||
|
||||
@Deprecated("Pass in a KeyIdentifier instead of keyId")
|
||||
@Throws(PGPException::class)
|
||||
fun setExpirationDateOfSubkey(
|
||||
expiration: Date?,
|
||||
keyId: Long,
|
||||
protector: SecretKeyRingProtector
|
||||
) = setExpirationDateOfSubkey(expiration, KeyIdentifier(keyId), protector)
|
||||
|
||||
/**
|
||||
* Set the expiration date for the subkey identified by the given keyId to the given expiration
|
||||
* date. If the key is supposed to never expire, then an expiration date of null is expected.
|
||||
|
@ -484,7 +513,7 @@ interface SecretKeyRingEditorInterface {
|
|||
@Throws(PGPException::class)
|
||||
fun setExpirationDateOfSubkey(
|
||||
expiration: Date?,
|
||||
keyId: Long,
|
||||
keyId: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector
|
||||
): SecretKeyRingEditorInterface
|
||||
|
||||
|
@ -502,7 +531,7 @@ interface SecretKeyRingEditorInterface {
|
|||
fun createMinimalRevocationCertificate(
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPPublicKeyRing
|
||||
): OpenPGPCertificate
|
||||
|
||||
/**
|
||||
* Create a detached revocation certificate, which can be used to revoke the whole key. The
|
||||
|
@ -517,13 +546,21 @@ interface SecretKeyRingEditorInterface {
|
|||
fun createRevocation(
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature
|
||||
): OpenPGPSignature
|
||||
|
||||
@Throws(PGPException::class)
|
||||
@Deprecated("Pass in a KeyIdentifier instead of a keyId")
|
||||
fun createRevocation(
|
||||
subkeyId: Long,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
) = createRevocation(KeyIdentifier(subkeyId), protector, revocationAttributes)
|
||||
|
||||
/**
|
||||
* Create a detached revocation certificate, which can be used to revoke the specified subkey.
|
||||
* The original key will not be modified by this method.
|
||||
*
|
||||
* @param subkeyId id of the subkey to be revoked
|
||||
* @param subkeyIdentifier id of the subkey to be revoked
|
||||
* @param protector protector to unlock the primary key.
|
||||
* @param revocationAttributes reason for the revocation
|
||||
* @return revocation certificate
|
||||
|
@ -531,16 +568,24 @@ interface SecretKeyRingEditorInterface {
|
|||
*/
|
||||
@Throws(PGPException::class)
|
||||
fun createRevocation(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature
|
||||
): OpenPGPSignature
|
||||
|
||||
@Deprecated("Pass in a KeyIdentifier instead of keyId")
|
||||
@Throws(PGPException::class)
|
||||
fun createRevocation(
|
||||
subkeyId: Long,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
) = createRevocation(KeyIdentifier(subkeyId), protector, callback)
|
||||
|
||||
/**
|
||||
* Create a detached revocation certificate, which can be used to revoke the specified subkey.
|
||||
* The original key will not be modified by this method.
|
||||
*
|
||||
* @param subkeyId id of the subkey to be revoked
|
||||
* @param subkeyIdentifier id of the subkey to be revoked
|
||||
* @param protector protector to unlock the primary key.
|
||||
* @param callback callback to modify the subpackets of the revocation certificate.
|
||||
* @return revocation certificate
|
||||
|
@ -548,10 +593,10 @@ interface SecretKeyRingEditorInterface {
|
|||
*/
|
||||
@Throws(PGPException::class)
|
||||
fun createRevocation(
|
||||
subkeyId: Long,
|
||||
subkeyIdentifier: KeyIdentifier,
|
||||
protector: SecretKeyRingProtector,
|
||||
callback: RevocationSignatureSubpackets.Callback?
|
||||
): PGPSignature
|
||||
): OpenPGPSignature
|
||||
|
||||
/**
|
||||
* Create a detached revocation certificate, which can be used to revoke the specified subkey.
|
||||
|
@ -568,7 +613,7 @@ interface SecretKeyRingEditorInterface {
|
|||
subkeyFingerprint: OpenPgpFingerprint,
|
||||
protector: SecretKeyRingProtector,
|
||||
revocationAttributes: RevocationAttributes?
|
||||
): PGPSignature
|
||||
): OpenPGPSignature
|
||||
|
||||
/**
|
||||
* Change the passphrase of the whole key ring.
|
||||
|
@ -676,7 +721,7 @@ interface SecretKeyRingEditorInterface {
|
|||
*
|
||||
* @return the key
|
||||
*/
|
||||
fun done(): PGPSecretKeyRing
|
||||
fun done(): OpenPGPKey
|
||||
|
||||
fun addSubKey(
|
||||
keySpec: KeySpec,
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.pgpainless.key.protection
|
|||
import org.bouncycastle.bcpg.KeyIdentifier
|
||||
import org.bouncycastle.openpgp.PGPKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSecretKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
|
||||
import org.pgpainless.util.Passphrase
|
||||
|
||||
|
@ -32,6 +33,25 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
|
|||
) : super(passphraseProvider, settings)
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
fun forKey(
|
||||
cert: OpenPGPCertificate,
|
||||
passphrase: Passphrase
|
||||
): PasswordBasedSecretKeyRingProtector {
|
||||
return object : SecretKeyPassphraseProvider {
|
||||
|
||||
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
|
||||
return if (hasPassphrase(keyIdentifier)) passphrase else null
|
||||
}
|
||||
|
||||
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
|
||||
return cert.getKey(keyIdentifier) != null
|
||||
}
|
||||
}
|
||||
.let { PasswordBasedSecretKeyRingProtector(it) }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun forKey(
|
||||
keyRing: PGPKeyRing,
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.bouncycastle.openpgp.PGPSecretKey
|
|||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.openpgp.api.KeyPassphraseProvider
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
|
||||
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
|
||||
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
|
||||
|
@ -105,6 +106,10 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
|
|||
KeyRingProtectionSettings.secureDefaultSettings(),
|
||||
missingPassphraseCallback)
|
||||
|
||||
@JvmStatic
|
||||
fun unlockEachKeyWith(passphrase: Passphrase, keys: OpenPGPKey): SecretKeyRingProtector =
|
||||
fromPassphraseMap(keys.secretKeys.keys.associateWith { passphrase })
|
||||
|
||||
/**
|
||||
* Use the provided passphrase to lock/unlock all keys in the provided key ring.
|
||||
*
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.util.function.Predicate
|
|||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPPrimaryKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
|
@ -63,4 +65,7 @@ class PrimaryKeyBindingSignatureBuilder :
|
|||
fun build(primaryKey: PGPPublicKey): PGPSignature =
|
||||
buildAndInitSignatureGenerator()
|
||||
.generateCertification(primaryKey, signingKey.publicKey.pgpPublicKey)
|
||||
|
||||
fun build(primaryKey: OpenPGPPrimaryKey): OpenPGPComponentSignature =
|
||||
OpenPGPComponentSignature(build(primaryKey.pgpPublicKey), primaryKey, primaryKey)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,11 @@ import java.util.function.Predicate
|
|||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPUserId
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.SignatureType
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector
|
||||
|
@ -59,6 +63,11 @@ constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun build(revokeeKey: OpenPGPComponentKey): OpenPGPSignature {
|
||||
return OpenPGPComponentSignature(
|
||||
build(revokeeKey.pgpPublicKey), signingKey.publicKey, revokeeKey)
|
||||
}
|
||||
|
||||
@Throws(PGPException::class)
|
||||
fun build(revokeeUserId: CharSequence): PGPSignature =
|
||||
buildAndInitSignatureGenerator()
|
||||
|
@ -69,6 +78,11 @@ constructor(
|
|||
}
|
||||
.generateCertification(revokeeUserId.toString(), signingKey.publicKey.pgpPublicKey)
|
||||
|
||||
fun build(revokeeUserId: OpenPGPUserId): OpenPGPComponentSignature {
|
||||
return OpenPGPComponentSignature(
|
||||
build(revokeeUserId.userId), signingKey.publicKey, revokeeUserId)
|
||||
}
|
||||
|
||||
init {
|
||||
hashedSubpackets.setRevocable(false)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ import java.util.function.Predicate
|
|||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
|
@ -77,4 +79,7 @@ class SubkeyBindingSignatureBuilder : AbstractSignatureBuilder<SubkeyBindingSign
|
|||
fun build(subkey: PGPPublicKey): PGPSignature =
|
||||
buildAndInitSignatureGenerator()
|
||||
.generateCertification(signingKey.publicKey.pgpPublicKey, subkey)
|
||||
|
||||
fun build(subkey: OpenPGPComponentKey): OpenPGPComponentSignature =
|
||||
OpenPGPComponentSignature(build(subkey.pgpPublicKey), signingKey.publicKey, subkey)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package org.pgpainless.util.selection.userid
|
|||
|
||||
import java.util.function.Predicate
|
||||
import org.bouncycastle.openpgp.PGPKeyRing
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate
|
||||
import org.pgpainless.PGPainless
|
||||
|
||||
abstract class SelectUserId : Predicate<String>, (String) -> Boolean {
|
||||
|
@ -72,6 +73,14 @@ abstract class SelectUserId : Predicate<String>, (String) -> Boolean {
|
|||
@JvmStatic
|
||||
fun byEmail(email: CharSequence) = or(exactMatch(email), containsEmailAddress(email))
|
||||
|
||||
@JvmStatic
|
||||
fun validUserId(key: OpenPGPCertificate) =
|
||||
object : SelectUserId() {
|
||||
private val info = PGPainless.getInstance().inspect(key)
|
||||
|
||||
override fun invoke(userId: String): Boolean = info.isUserIdValid(userId)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun validUserId(keyRing: PGPKeyRing) =
|
||||
object : SelectUserId() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.bouncycastle.openpgp.PGPSecretKey;
|
|||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -130,16 +131,16 @@ public class SigningTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testSignWithRevokedUserIdFails()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice", "password123")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("alice", "password123");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(
|
||||
Passphrase.fromPassword("password123"));
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeUserId("alice", protector)
|
||||
.done();
|
||||
|
||||
final PGPSecretKeyRing fSecretKeys = secretKeys;
|
||||
final OpenPGPKey fSecretKeys = secretKeys;
|
||||
|
||||
SigningOptions opts = SigningOptions.get();
|
||||
// "alice" has been revoked
|
||||
|
|
|
@ -9,14 +9,14 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
|||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.bouncycastle.bcpg.KeyIdentifier;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -34,25 +34,25 @@ import org.pgpainless.util.Passphrase;
|
|||
|
||||
/**
|
||||
* PGPainless offers a simple API to modify keys by adding and replacing signatures and/or subkeys.
|
||||
* The main entry point to this API is {@link PGPainless#modifyKeyRing(PGPSecretKeyRing)}.
|
||||
* The main entry point to this API is {@link PGPainless#modify(OpenPGPKey)}.
|
||||
*/
|
||||
public class ModifyKeys {
|
||||
|
||||
private final String userId = "alice@pgpainless.org";
|
||||
private final String originalPassphrase = "p4ssw0rd";
|
||||
private PGPSecretKeyRing secretKey;
|
||||
private long primaryKeyId;
|
||||
private OpenPGPKey secretKey;
|
||||
private KeyIdentifier primaryKeyId;
|
||||
private KeyIdentifier encryptionSubkeyId;
|
||||
private KeyIdentifier signingSubkeyId;
|
||||
|
||||
@BeforeEach
|
||||
public void generateKey() {
|
||||
secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing(userId, originalPassphrase)
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
secretKey = api.generateKey()
|
||||
.modernKeyRing(userId, originalPassphrase);
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey);
|
||||
primaryKeyId = info.getKeyIdentifier().getKeyId();
|
||||
KeyRingInfo info = api.inspect(secretKey);
|
||||
primaryKeyId = info.getKeyIdentifier();
|
||||
encryptionSubkeyId = info.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getKeyIdentifier();
|
||||
signingSubkeyId = info.getSigningSubkeys().get(0).getKeyIdentifier();
|
||||
}
|
||||
|
@ -63,9 +63,9 @@ public class ModifyKeys {
|
|||
@Test
|
||||
public void extractPublicKey() {
|
||||
// the certificate consists of only the public keys
|
||||
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey);
|
||||
OpenPGPCertificate certificate = secretKey.toCertificate();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(certificate);
|
||||
KeyRingInfo info = PGPainless.getInstance().inspect(certificate);
|
||||
assertFalse(info.isSecretKey());
|
||||
}
|
||||
|
||||
|
@ -73,11 +73,11 @@ public class ModifyKeys {
|
|||
* This example demonstrates how to export a secret key or certificate to an ASCII armored string.
|
||||
*/
|
||||
@Test
|
||||
public void toAsciiArmoredString() {
|
||||
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey);
|
||||
public void toAsciiArmoredString() throws IOException {
|
||||
OpenPGPCertificate certificate = secretKey.toCertificate();
|
||||
|
||||
String asciiArmoredSecretKey = PGPainless.asciiArmor(secretKey);
|
||||
String asciiArmoredCertificate = PGPainless.asciiArmor(certificate);
|
||||
String asciiArmoredSecretKey = secretKey.toAsciiArmoredString();
|
||||
String asciiArmoredCertificate = certificate.toAsciiArmoredString();
|
||||
|
||||
assertTrue(asciiArmoredSecretKey.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK-----"));
|
||||
assertTrue(asciiArmoredCertificate.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----"));
|
||||
|
@ -88,7 +88,8 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void changePassphrase() throws PGPException {
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
secretKey = api.modify(secretKey)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.fromPassword(originalPassphrase))
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("n3wP4ssW0rD"))
|
||||
|
@ -96,9 +97,9 @@ public class ModifyKeys {
|
|||
|
||||
// Old passphrase no longer works
|
||||
assertThrows(WrongPassphraseException.class, () ->
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(), Passphrase.fromPassword(originalPassphrase)));
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getPGPSecretKeyRing().getSecretKey(), Passphrase.fromPassword(originalPassphrase)));
|
||||
// But the new one does
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(), Passphrase.fromPassword("n3wP4ssW0rD"));
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getPGPSecretKeyRing().getSecretKey(), Passphrase.fromPassword("n3wP4ssW0rD"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,9 +108,10 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void changeSingleSubkeyPassphrase() throws PGPException {
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
secretKey = api.modify(secretKey)
|
||||
// Here we change the passphrase of the encryption subkey
|
||||
.changeSubKeyPassphraseFromOldPassphrase(encryptionSubkeyId.getKeyId(), Passphrase.fromPassword(originalPassphrase))
|
||||
.changeSubKeyPassphraseFromOldPassphrase(encryptionSubkeyId, Passphrase.fromPassword(originalPassphrase))
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("cryptP4ssphr4s3"))
|
||||
.done();
|
||||
|
@ -117,12 +119,12 @@ public class ModifyKeys {
|
|||
// encryption key can now only be unlocked using the new passphrase
|
||||
assertThrows(WrongPassphraseException.class, () ->
|
||||
UnlockSecretKey.unlockSecretKey(
|
||||
secretKey.getSecretKey(encryptionSubkeyId), Passphrase.fromPassword(originalPassphrase)));
|
||||
secretKey.getSecretKey(encryptionSubkeyId).getPGPSecretKey(), Passphrase.fromPassword(originalPassphrase)));
|
||||
UnlockSecretKey.unlockSecretKey(
|
||||
secretKey.getSecretKey(encryptionSubkeyId), Passphrase.fromPassword("cryptP4ssphr4s3"));
|
||||
secretKey.getSecretKey(encryptionSubkeyId).getPGPSecretKey(), Passphrase.fromPassword("cryptP4ssphr4s3"));
|
||||
// primary key remains unchanged
|
||||
UnlockSecretKey.unlockSecretKey(
|
||||
secretKey.getSecretKey(primaryKeyId), Passphrase.fromPassword(originalPassphrase));
|
||||
secretKey.getSecretKey(primaryKeyId).getPGPSecretKey(), Passphrase.fromPassword(originalPassphrase));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,13 +132,14 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void addUserId() throws PGPException {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
SecretKeyRingProtector protector =
|
||||
SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.addUserId("additional@user.id", protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey);
|
||||
KeyRingInfo info = api.inspect(secretKey);
|
||||
assertTrue(info.isUserIdValid("additional@user.id"));
|
||||
assertFalse(info.isUserIdValid("another@user.id"));
|
||||
}
|
||||
|
@ -156,11 +159,12 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void addSubkey() {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
// Protector for unlocking the existing secret key
|
||||
SecretKeyRingProtector protector =
|
||||
SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
|
||||
Passphrase subkeyPassphrase = Passphrase.fromPassword("subk3yP4ssphr4s3");
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.addSubKey(
|
||||
KeySpec.getBuilder(KeyType.ECDH(EllipticCurve._BRAINPOOLP512R1), KeyFlag.ENCRYPT_COMMS)
|
||||
.build(),
|
||||
|
@ -168,7 +172,7 @@ public class ModifyKeys {
|
|||
protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey);
|
||||
KeyRingInfo info = api.inspect(secretKey);
|
||||
assertEquals(4, info.getSecretKeys().size());
|
||||
assertEquals(4, info.getPublicKeys().size());
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> encryptionSubkeys = info.getEncryptionSubkeys(EncryptionPurpose.COMMUNICATIONS);
|
||||
|
@ -176,7 +180,7 @@ public class ModifyKeys {
|
|||
OpenPGPCertificate.OpenPGPComponentKey addedKey = encryptionSubkeys.stream()
|
||||
.filter(it -> !it.getKeyIdentifier().matches(encryptionSubkeyId)).findFirst()
|
||||
.get();
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(addedKey.getKeyIdentifier()), subkeyPassphrase);
|
||||
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(addedKey.getKeyIdentifier()).getPGPSecretKey(), subkeyPassphrase);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -185,15 +189,16 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void setKeyExpirationDate() {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
Date expirationDate = DateUtil.parseUTCDate("2030-06-24 12:44:56 UTC");
|
||||
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector
|
||||
.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.setExpirationDate(expirationDate, protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey);
|
||||
KeyRingInfo info = api.inspect(secretKey);
|
||||
assertEquals(DateUtil.formatUTCDate(expirationDate),
|
||||
DateUtil.formatUTCDate(info.getPrimaryKeyExpirationDate()));
|
||||
assertEquals(DateUtil.formatUTCDate(expirationDate),
|
||||
|
@ -207,19 +212,20 @@ public class ModifyKeys {
|
|||
*/
|
||||
@Test
|
||||
public void revokeUserId() throws PGPException {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith(
|
||||
Passphrase.fromPassword(originalPassphrase), secretKey);
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.addUserId("alcie@pgpainless.org", protector)
|
||||
.done();
|
||||
// Initially the user-id is valid
|
||||
assertTrue(PGPainless.inspectKeyRing(secretKey).isUserIdValid("alcie@pgpainless.org"));
|
||||
assertTrue(api.inspect(secretKey).isUserIdValid("alcie@pgpainless.org"));
|
||||
|
||||
// Revoke the second user-id
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.revokeUserId("alcie@pgpainless.org", protector)
|
||||
.done();
|
||||
// Now the user-id is no longer valid
|
||||
assertFalse(PGPainless.inspectKeyRing(secretKey).isUserIdValid("alcie@pgpainless.org"));
|
||||
assertFalse(api.inspect(secretKey).isUserIdValid("alcie@pgpainless.org"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,11 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
|||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
|
||||
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
|
||||
public class TestKeys {
|
||||
|
@ -265,6 +268,10 @@ public class TestKeys {
|
|||
"=1d67\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||
|
||||
public static OpenPGPKey getJulietKey() throws PGPException, IOException {
|
||||
return PGPainless.getInstance().toKey(getJulietSecretKeyRing());
|
||||
}
|
||||
|
||||
public static PGPSecretKeyRing getJulietSecretKeyRing() throws IOException, PGPException {
|
||||
if (julietSecretKeyRing == null) {
|
||||
julietSecretKeyRing = new PGPSecretKeyRing(
|
||||
|
@ -281,6 +288,10 @@ public class TestKeys {
|
|||
return julietSecretKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPCertificate getJulietCertificate() throws IOException {
|
||||
return PGPainless.getInstance().toCertificate(getJulietPublicKeyRing());
|
||||
}
|
||||
|
||||
public static PGPPublicKeyRing getJulietPublicKeyRing() throws IOException {
|
||||
if (julietPublicKeyRing == null) {
|
||||
julietPublicKeyRing = new PGPPublicKeyRing(
|
||||
|
@ -297,6 +308,10 @@ public class TestKeys {
|
|||
return julietPublicKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPKey getRomeoKey() throws PGPException, IOException {
|
||||
return PGPainless.getInstance().toKey(getRomeoSecretKeyRing());
|
||||
}
|
||||
|
||||
public static PGPSecretKeyRing getRomeoSecretKeyRing() throws IOException, PGPException {
|
||||
if (romeoSecretKeyRing == null) {
|
||||
romeoSecretKeyRing = new PGPSecretKeyRing(
|
||||
|
@ -313,6 +328,10 @@ public class TestKeys {
|
|||
return romeoSecretKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPCertificate getRomeoCertificate() throws IOException {
|
||||
return PGPainless.getInstance().toCertificate(getRomeoPublicKeyRing());
|
||||
}
|
||||
|
||||
public static PGPPublicKeyRing getRomeoPublicKeyRing() throws IOException {
|
||||
if (romeoPublicKeyRing == null) {
|
||||
romeoPublicKeyRing = new PGPPublicKeyRing(
|
||||
|
@ -329,6 +348,10 @@ public class TestKeys {
|
|||
return romeoPublicKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPKey getEmilKey() throws PGPException, IOException {
|
||||
return PGPainless.getInstance().toKey(getEmilSecretKeyRing());
|
||||
}
|
||||
|
||||
public static PGPSecretKeyRing getEmilSecretKeyRing() throws IOException, PGPException {
|
||||
if (emilSecretKeyRing == null) {
|
||||
emilSecretKeyRing = new PGPSecretKeyRing(
|
||||
|
@ -345,6 +368,10 @@ public class TestKeys {
|
|||
return emilSecretKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPCertificate getEmilCertificate() throws IOException {
|
||||
return PGPainless.getInstance().toCertificate(getEmilPublicKeyRing());
|
||||
}
|
||||
|
||||
public static PGPPublicKeyRing getEmilPublicKeyRing() throws IOException {
|
||||
if (emilPublicKeyRing == null) {
|
||||
emilPublicKeyRing = new PGPPublicKeyRing(
|
||||
|
@ -361,6 +388,10 @@ public class TestKeys {
|
|||
return emilPublicKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPKey getCryptieKey() throws PGPException, IOException {
|
||||
return PGPainless.getInstance().toKey(getCryptieSecretKeyRing());
|
||||
}
|
||||
|
||||
public static PGPSecretKeyRing getCryptieSecretKeyRing() throws IOException, PGPException {
|
||||
if (cryptieSecretKeyRing == null) {
|
||||
cryptieSecretKeyRing = new PGPSecretKeyRing(
|
||||
|
@ -377,6 +408,10 @@ public class TestKeys {
|
|||
return cryptieSecretKeyRingCollection;
|
||||
}
|
||||
|
||||
public static OpenPGPCertificate getCryptieCertificate() throws IOException {
|
||||
return PGPainless.getInstance().toCertificate(getCryptiePublicKeyRing());
|
||||
}
|
||||
|
||||
public static PGPPublicKeyRing getCryptiePublicKeyRing() throws IOException {
|
||||
if (cryptiePublicKeyRing == null) {
|
||||
cryptiePublicKeyRing = new PGPPublicKeyRing(
|
||||
|
|
|
@ -18,10 +18,10 @@ import java.util.List;
|
|||
|
||||
import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
|
@ -39,10 +39,10 @@ public class KeyGenerationSubpacketsTest {
|
|||
@Test
|
||||
public void verifyDefaultSubpacketsForUserIdSignatures()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
Date plus1Sec = new Date(secretKeys.getPublicKey().getCreationTime().getTime() + 1000);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
Date plus1Sec = new Date(secretKeys.getPrimarySecretKey().getCreationTime().getTime() + 1000);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
PGPSignature userIdSig = info.getLatestUserIdCertification("Alice");
|
||||
assertNotNull(userIdSig);
|
||||
int keyFlags = userIdSig.getHashedSubPackets().getKeyFlags();
|
||||
|
@ -54,7 +54,7 @@ public class KeyGenerationSubpacketsTest {
|
|||
|
||||
assertEquals("Alice", info.getPrimaryUserId());
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, plus1Sec)
|
||||
secretKeys = api.modify(secretKeys, plus1Sec)
|
||||
.addUserId("Bob",
|
||||
new SelfSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
|
@ -66,7 +66,7 @@ public class KeyGenerationSubpacketsTest {
|
|||
.addUserId("Alice", SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, plus1Sec);
|
||||
info = api.inspect(secretKeys, plus1Sec);
|
||||
|
||||
userIdSig = info.getLatestUserIdCertification("Alice");
|
||||
assertNotNull(userIdSig);
|
||||
|
@ -89,7 +89,7 @@ public class KeyGenerationSubpacketsTest {
|
|||
|
||||
Date now = plus1Sec;
|
||||
Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.addUserId("Alice", new SelfSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
|
||||
|
@ -98,7 +98,7 @@ public class KeyGenerationSubpacketsTest {
|
|||
}
|
||||
}, SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t1);
|
||||
info = api.inspect(secretKeys, t1);
|
||||
assertEquals("Alice", info.getPrimaryUserId());
|
||||
assertEquals(Collections.singleton(HashAlgorithm.SHA1), info.getPreferredHashAlgorithms("Alice"));
|
||||
}
|
||||
|
@ -106,29 +106,29 @@ public class KeyGenerationSubpacketsTest {
|
|||
@Test
|
||||
public void verifyDefaultSubpacketsForSubkeyBindingSignatures()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> keysBefore = info.getPublicKeys();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addSubKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA).build(),
|
||||
Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(secretKeys);
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> keysAfter = new ArrayList<>(info.getPublicKeys());
|
||||
keysAfter.removeAll(keysBefore);
|
||||
assertEquals(1, keysAfter.size());
|
||||
OpenPGPCertificate.OpenPGPComponentKey newSigningKey = keysAfter.get(0);
|
||||
|
||||
PGPSignature bindingSig = info.getCurrentSubkeyBindingSignature(newSigningKey.getKeyIdentifier().getKeyId());
|
||||
PGPSignature bindingSig = info.getCurrentSubkeyBindingSignature(newSigningKey.getKeyIdentifier());
|
||||
assertNotNull(bindingSig);
|
||||
assureSignatureHasDefaultSubpackets(bindingSig, secretKeys, KeyFlag.SIGN_DATA);
|
||||
assertNotNull(bindingSig.getHashedSubPackets().getEmbeddedSignatures().get(0));
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addSubKey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS).build(),
|
||||
Passphrase.emptyPassphrase(),
|
||||
new SelfSignatureSubpackets.Callback() {
|
||||
|
@ -139,24 +139,24 @@ public class KeyGenerationSubpacketsTest {
|
|||
}, SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(secretKeys);
|
||||
keysAfter = new ArrayList<>(info.getPublicKeys());
|
||||
keysAfter.removeAll(keysBefore);
|
||||
keysAfter.remove(newSigningKey);
|
||||
assertEquals(1, keysAfter.size());
|
||||
OpenPGPCertificate.OpenPGPComponentKey newEncryptionKey = keysAfter.get(0);
|
||||
bindingSig = info.getCurrentSubkeyBindingSignature(newEncryptionKey.getKeyIdentifier().getKeyId());
|
||||
bindingSig = info.getCurrentSubkeyBindingSignature(newEncryptionKey.getKeyIdentifier());
|
||||
assertNotNull(bindingSig);
|
||||
assertNull(bindingSig.getHashedSubPackets().getIssuerFingerprint());
|
||||
assertEquals(KeyFlag.toBitmask(KeyFlag.ENCRYPT_COMMS), bindingSig.getHashedSubPackets().getKeyFlags());
|
||||
}
|
||||
|
||||
private void assureSignatureHasDefaultSubpackets(PGPSignature signature, PGPSecretKeyRing secretKeys, KeyFlag... keyFlags) {
|
||||
private void assureSignatureHasDefaultSubpackets(PGPSignature signature, OpenPGPKey secretKeys, KeyFlag... keyFlags) {
|
||||
PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets();
|
||||
assertNotNull(hashedSubpackets.getIssuerFingerprint());
|
||||
assertEquals(secretKeys.getPublicKey().getKeyID(), hashedSubpackets.getIssuerKeyID());
|
||||
assertEquals(secretKeys.getKeyIdentifier().getKeyId(), hashedSubpackets.getIssuerKeyID());
|
||||
assertArrayEquals(
|
||||
secretKeys.getPublicKey().getFingerprint(),
|
||||
secretKeys.getFingerprint(),
|
||||
hashedSubpackets.getIssuerFingerprint().getFingerprint());
|
||||
assertEquals(hashedSubpackets.getKeyFlags(), KeyFlag.toBitmask(keyFlags));
|
||||
}
|
||||
|
|
|
@ -24,9 +24,7 @@ import java.util.Set;
|
|||
|
||||
import org.bouncycastle.bcpg.KeyIdentifier;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
|
@ -50,7 +48,6 @@ import org.pgpainless.key.generation.type.ecc.EllipticCurve;
|
|||
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
import org.pgpainless.key.util.UserId;
|
||||
import org.pgpainless.util.DateUtil;
|
||||
|
@ -62,11 +59,12 @@ public class KeyRingInfoTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testWithEmilsKeys() throws IOException, PGPException {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPPublicKeyRing publicKeys = TestKeys.getEmilPublicKeyRing();
|
||||
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo pInfo = PGPainless.inspectKeyRing(publicKeys);
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
OpenPGPCertificate publicKeys = TestKeys.getEmilCertificate();
|
||||
KeyRingInfo sInfo = api.inspect(secretKeys);
|
||||
KeyRingInfo pInfo = api.inspect(publicKeys);
|
||||
|
||||
assertEquals(TestKeys.EMIL_KEY_ID, sInfo.getKeyIdentifier().getKeyId());
|
||||
assertEquals(TestKeys.EMIL_KEY_ID, pInfo.getKeyIdentifier().getKeyId());
|
||||
|
@ -108,13 +106,13 @@ public class KeyRingInfoTest {
|
|||
assertNull(sInfo.getRevocationDate());
|
||||
assertNull(pInfo.getRevocationDate());
|
||||
Date revocationDate = DateUtil.now();
|
||||
PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys).revoke(
|
||||
OpenPGPKey revoked = api.modify(secretKeys).revoke(
|
||||
new UnprotectedKeysProtector(),
|
||||
RevocationAttributes.createKeyRevocation()
|
||||
.withReason(RevocationAttributes.Reason.KEY_RETIRED)
|
||||
.withoutDescription()
|
||||
).done();
|
||||
KeyRingInfo rInfo = PGPainless.inspectKeyRing(revoked);
|
||||
KeyRingInfo rInfo = api.inspect(revoked);
|
||||
assertNotNull(rInfo.getRevocationDate());
|
||||
assertEquals(revocationDate.getTime(), rInfo.getRevocationDate().getTime(), 5);
|
||||
assertEquals(revocationDate.getTime(), rInfo.getLastModified().getTime(), 5);
|
||||
|
@ -125,32 +123,34 @@ public class KeyRingInfoTest {
|
|||
|
||||
@Test
|
||||
public void testIsFullyDecrypted() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
assertTrue(info.isFullyDecrypted());
|
||||
|
||||
secretKeys = encryptSecretKeys(secretKeys);
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
secretKeys = encryptSecretKeys(secretKeys, api);
|
||||
info = api.inspect(secretKeys);
|
||||
|
||||
assertFalse(info.isFullyDecrypted());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsFullyEncrypted() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
assertFalse(info.isFullyEncrypted());
|
||||
|
||||
secretKeys = encryptSecretKeys(secretKeys);
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
secretKeys = encryptSecretKeys(secretKeys, api);
|
||||
info = api.inspect(secretKeys);
|
||||
|
||||
assertTrue(info.isFullyEncrypted());
|
||||
}
|
||||
|
||||
private static PGPSecretKeyRing encryptSecretKeys(PGPSecretKeyRing secretKeys) throws PGPException {
|
||||
return PGPainless.modifyKeyRing(secretKeys)
|
||||
private static OpenPGPKey encryptSecretKeys(OpenPGPKey secretKeys, PGPainless api) throws PGPException {
|
||||
return api.modify(secretKeys)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase())
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("sw0rdf1sh"))
|
||||
|
@ -160,27 +160,29 @@ public class KeyRingInfoTest {
|
|||
|
||||
@Test
|
||||
public void testGetSecretKey() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
OpenPGPCertificate publicKeys = secretKeys.toCertificate();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
OpenPGPKey.OpenPGPSecretKey primarySecretKey = info.getSecretKey();
|
||||
assertNotNull(primarySecretKey);
|
||||
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys), primarySecretKey.getPGPSecretKey());
|
||||
assertEquals(secretKeys.getPrimarySecretKey().getPGPSecretKey(), primarySecretKey.getPGPSecretKey());
|
||||
|
||||
info = PGPainless.inspectKeyRing(publicKeys);
|
||||
info = api.inspect(publicKeys);
|
||||
assertNull(info.getSecretKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPublicKey() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
assertEquals(KeyRingUtils.requirePrimaryPublicKeyFrom(secretKeys), info.getPrimaryKey().getPGPPublicKey());
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertEquals(secretKeys.getPrimaryKey().getPGPPublicKey(), info.getPrimaryKey().getPGPPublicKey());
|
||||
|
||||
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys),
|
||||
KeyRingUtils.requireSecretKeyFrom(secretKeys, secretKeys.getPublicKey().getKeyID()));
|
||||
assertEquals(secretKeys.getPrimarySecretKey().getPGPSecretKey(),
|
||||
secretKeys.getPGPSecretKeyRing().getSecretKey(secretKeys.getKeyIdentifier()));
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
|
@ -224,8 +226,8 @@ public class KeyRingInfoTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testGetKeysWithFlagsAndExpiry() {
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing()
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(
|
||||
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
|
||||
.addSubkey(KeySpec.getBuilder(
|
||||
|
@ -234,10 +236,9 @@ public class KeyRingInfoTest {
|
|||
.addSubkey(KeySpec.getBuilder(
|
||||
KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.SIGN_DATA))
|
||||
.addUserId(UserId.builder().withName("Alice").withEmail("alice@pgpainless.org").build())
|
||||
.build()
|
||||
.getPGPSecretKeyRing();
|
||||
.build();
|
||||
|
||||
Iterator<PGPSecretKey> keys = secretKeys.iterator();
|
||||
Iterator<PGPSecretKey> keys = secretKeys.getPGPSecretKeyRing().iterator();
|
||||
Date now = DateUtil.now();
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
|
@ -255,11 +256,11 @@ public class KeyRingInfoTest {
|
|||
PGPSecretKey signingKey = keys.next();
|
||||
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDate(primaryKeyExpiration, protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = new KeyRingInfo(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> encryptionKeys = info.getKeysWithKeyFlag(KeyFlag.ENCRYPT_STORAGE);
|
||||
assertEquals(1, encryptionKeys.size());
|
||||
|
@ -354,9 +355,10 @@ public class KeyRingInfoTest {
|
|||
"crH02GDG8CotAnEHkLTz9GPO80q8mowzBV0EtHsXb4TeAFw5T5Qd0a5I+wk=\n" +
|
||||
"=Vcb3\n" +
|
||||
"-----END PGP ARMORED FILE-----\n";
|
||||
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2021-10-10 00:00:00 UTC"));
|
||||
KeyRingInfo info = api.inspect(certificate, DateUtil.parseUTCDate("2021-10-10 00:00:00 UTC"));
|
||||
// Subkey is hard revoked
|
||||
assertFalse(info.isKeyValidlyBound(new KeyIdentifier(5364407983539305061L)));
|
||||
}
|
||||
|
@ -434,14 +436,15 @@ public class KeyRingInfoTest {
|
|||
"=7Feh\n" +
|
||||
"-----END PGP ARMORED FILE-----\n";
|
||||
|
||||
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
|
||||
final KeyIdentifier subkeyId = new KeyIdentifier(5364407983539305061L);
|
||||
|
||||
KeyRingInfo inspectDuringRevokedPeriod = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2019-01-02 00:00:00 UTC"));
|
||||
KeyRingInfo inspectDuringRevokedPeriod = api.inspect(certificate, DateUtil.parseUTCDate("2019-01-02 00:00:00 UTC"));
|
||||
assertFalse(inspectDuringRevokedPeriod.isKeyValidlyBound(subkeyId));
|
||||
assertNotNull(inspectDuringRevokedPeriod.getSubkeyRevocationSignature(subkeyId));
|
||||
|
||||
KeyRingInfo inspectAfterRebinding = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2020-01-02 00:00:00 UTC"));
|
||||
KeyRingInfo inspectAfterRebinding = api.inspect(certificate, DateUtil.parseUTCDate("2020-01-02 00:00:00 UTC"));
|
||||
assertTrue(inspectAfterRebinding.isKeyValidlyBound(subkeyId));
|
||||
}
|
||||
|
||||
|
@ -518,9 +521,10 @@ public class KeyRingInfoTest {
|
|||
"=MhJL\n" +
|
||||
"-----END PGP ARMORED FILE-----\n";
|
||||
|
||||
OpenPGPCertificate keys = PGPainless.getInstance().readKey().parseCertificate(KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate keys = api.readKey().parseCertificate(KEY);
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(keys);
|
||||
KeyRingInfo info = api.inspect(keys);
|
||||
// Primary key is hard revoked
|
||||
assertFalse(info.isKeyValidlyBound(keys.getKeyIdentifier()));
|
||||
assertFalse(info.isFullyEncrypted());
|
||||
|
@ -528,49 +532,48 @@ public class KeyRingInfoTest {
|
|||
|
||||
@Test
|
||||
public void getSecretKeyTest() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
OpenPGPKey key = new OpenPGPKey(secretKeys);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
OpenPgpV4Fingerprint primaryKeyFingerprint = new OpenPgpV4Fingerprint(secretKeys);
|
||||
OpenPGPKey.OpenPGPSecretKey primaryKey = info.getSecretKey(primaryKeyFingerprint);
|
||||
assertNotNull(primaryKey);
|
||||
assertEquals(key.getPrimarySecretKey().getKeyIdentifier(), primaryKey.getKeyIdentifier());
|
||||
assertEquals(secretKeys.getPrimarySecretKey().getKeyIdentifier(), primaryKey.getKeyIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLatestKeyCreationDate() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
Date latestCreationDate = DateUtil.parseUTCDate("2020-01-12 18:01:44 UTC");
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
|
||||
JUtils.assertDateEquals(latestCreationDate, info.getLatestKeyCreationDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExpirationDateForUse_SPLIT() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
|
||||
assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SPLIT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExpirationDateForUse_SHARED() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
|
||||
assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SHARED));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetExpirationDateForUse_NoSuchKey() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing()
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
|
||||
.addUserId("Alice")
|
||||
.setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
|
||||
.build()
|
||||
.getPGPSecretKeyRing();
|
||||
.build();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
assertThrows(NoSuchElementException.class, () -> info.getExpirationDateForUse(KeyFlag.ENCRYPT_COMMS));
|
||||
}
|
||||
|
@ -600,8 +603,8 @@ public class KeyRingInfoTest {
|
|||
"/+XL+qMMgLHaQ25aA11GVAkC\n" +
|
||||
"=7gbt\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||
|
||||
OpenPGPKey secretKeys = PGPainless.getInstance().readKey().parseKey(KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
|
||||
final KeyIdentifier pkid = new KeyIdentifier(6643807985200014832L);
|
||||
final KeyIdentifier skid1 = new KeyIdentifier(-2328413746552029063L);
|
||||
final KeyIdentifier skid2 = new KeyIdentifier(-3276877650571760552L);
|
||||
|
@ -611,7 +614,7 @@ public class KeyRingInfoTest {
|
|||
Arrays.asList(CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZIP, CompressionAlgorithm.UNCOMPRESSED));
|
||||
Set<SymmetricKeyAlgorithm> preferredSymmetricAlgorithms = new LinkedHashSet<>(
|
||||
Arrays.asList(SymmetricKeyAlgorithm.AES_256, SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128));
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
// Bob is an invalid userId
|
||||
assertThrows(NoSuchElementException.class, () -> info.getPreferredSymmetricKeyAlgorithms("Bob"));
|
||||
|
@ -694,10 +697,10 @@ public class KeyRingInfoTest {
|
|||
"C9h35EjDuD+1COXUOoW2B8LX6m2yf8cY72K70QgtGemj7UWhXL5u/wARAQAB\n" +
|
||||
"=A3B8\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----\n";
|
||||
|
||||
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
|
||||
OpenPgpV4Fingerprint unboundKey = new OpenPgpV4Fingerprint("D622C916384E0F6D364907E55D918BBD521CCD10");
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(certificate);
|
||||
KeyRingInfo info = api.inspect(certificate);
|
||||
|
||||
assertFalse(info.isKeyValidlyBound(unboundKey.getKeyIdentifier()));
|
||||
|
||||
|
@ -773,9 +776,9 @@ public class KeyRingInfoTest {
|
|||
"qDzPRwEAhdVBeryRUcwjgwHX0xmMFK7vLkdonn8BR2++nXBO2g8=\n" +
|
||||
"=ZRAy\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----\n";
|
||||
|
||||
OpenPGPKey secretKeys = PGPainless.getInstance().readKey().parseKey(KEY);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
List<String> emails = info.getEmailAddresses();
|
||||
assertEquals(emails, Arrays.asList("alice@email.tld", "alice@pgpainless.org", "alice@openpgp.org", "alice@rfc4880.spec"));
|
||||
|
@ -805,9 +808,9 @@ public class KeyRingInfoTest {
|
|||
"J5wP\n" +
|
||||
"=nFoO\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
OpenPGPCertificate cert = PGPainless.getInstance().readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(cert);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate cert = api.readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = api.inspect(cert);
|
||||
assertTrue(info.isUsableForEncryption());
|
||||
}
|
||||
|
||||
|
@ -833,9 +836,9 @@ public class KeyRingInfoTest {
|
|||
"2XO/hpB2T8VXFfFKwj7U9LGkX+ciLg==\n" +
|
||||
"=etPP\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
OpenPGPCertificate publicKeys = PGPainless.getInstance().readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(publicKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate publicKeys = api.readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = api.inspect(publicKeys);
|
||||
|
||||
assertTrue(info.isUsableForEncryption(EncryptionPurpose.COMMUNICATIONS));
|
||||
assertTrue(info.isUsableForEncryption(EncryptionPurpose.ANY));
|
||||
|
@ -870,8 +873,9 @@ public class KeyRingInfoTest {
|
|||
"AQCjeV+3VT+u1movwIYv4XkzB6gB+B2C+DK9nvG5sXZhBg==\n" +
|
||||
"=uqmO\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
OpenPGPCertificate publicKeys = PGPainless.getInstance().readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(publicKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPCertificate publicKeys = api.readKey().parseCertificate(CERT);
|
||||
KeyRingInfo info = api.inspect(publicKeys);
|
||||
|
||||
assertFalse(info.isUsableForEncryption());
|
||||
assertFalse(info.isUsableForEncryption(EncryptionPurpose.ANY));
|
||||
|
|
|
@ -7,7 +7,7 @@ package org.pgpainless.key.info;
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
|
@ -16,13 +16,13 @@ public class PrimaryUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testGetPrimaryUserId() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("alice@wonderland.lit")
|
||||
.getPGPSecretKeyRing();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("alice@wonderland.lit");
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("mad_alice@wonderland.lit", SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertEquals("alice@wonderland.lit", info.getPrimaryUserId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,12 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.bouncycastle.bcpg.KeyIdentifier;
|
||||
import org.bouncycastle.bcpg.SignatureSubpacketTags;
|
||||
import org.bouncycastle.bcpg.sig.RevocationReason;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.KeyFlag;
|
||||
|
@ -37,7 +38,8 @@ public class UserIdRevocationTest {
|
|||
|
||||
@Test
|
||||
public void testRevocationWithoutRevocationAttributes() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing()
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(
|
||||
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519),
|
||||
KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER))
|
||||
|
@ -45,28 +47,27 @@ public class UserIdRevocationTest {
|
|||
KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS))
|
||||
.addUserId("primary@key.id")
|
||||
.addUserId("secondary@key.id")
|
||||
.build()
|
||||
.getPGPSecretKeyRing();
|
||||
.build();
|
||||
|
||||
// make a copy with revoked subkey
|
||||
PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys)
|
||||
OpenPGPKey revoked = api.modify(secretKeys)
|
||||
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(revoked);
|
||||
KeyRingInfo info = api.inspect(revoked);
|
||||
List<String> userIds = info.getUserIds();
|
||||
assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds);
|
||||
assertTrue(info.isUserIdValid("primary@key.id"));
|
||||
assertFalse(info.isUserIdValid("sedondary@key.id"));
|
||||
assertFalse(info.isUserIdValid("tertiary@key.id"));
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(secretKeys);
|
||||
assertTrue(info.isUserIdValid("secondary@key.id")); // key on original secret key ring is still valid
|
||||
|
||||
revoked = PGPainless.modifyKeyRing(secretKeys)
|
||||
revoked = api.modify(secretKeys)
|
||||
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(revoked);
|
||||
info = api.inspect(revoked);
|
||||
userIds = info.getUserIds();
|
||||
assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds);
|
||||
assertTrue(info.isUserIdValid("primary@key.id"));
|
||||
|
@ -76,23 +77,23 @@ public class UserIdRevocationTest {
|
|||
|
||||
@Test
|
||||
public void testRevocationWithRevocationReason() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing()
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(
|
||||
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519),
|
||||
KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER))
|
||||
.addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS))
|
||||
.addUserId("primary@key.id")
|
||||
.addUserId("secondary@key.id")
|
||||
.build()
|
||||
.getPGPSecretKeyRing();
|
||||
.build();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector(),
|
||||
RevocationAttributes.createCertificateRevocation()
|
||||
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
|
||||
.withDescription("I lost my mail password"))
|
||||
.done();
|
||||
KeyRingInfo info = new KeyRingInfo(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
PGPSignature signature = info.getUserIdRevocation("secondary@key.id");
|
||||
assertNotNull(signature);
|
||||
|
@ -104,31 +105,31 @@ public class UserIdRevocationTest {
|
|||
|
||||
@Test
|
||||
public void unknownKeyThrowsIllegalArgumentException() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
|
||||
.forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
|
||||
|
||||
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
.revokeSubKey(1L, protector));
|
||||
assertThrows(NoSuchElementException.class, () -> PGPainless.getInstance().modify(secretKeys)
|
||||
.revokeSubKey(new KeyIdentifier(1L), protector));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownUserIdThrowsNoSuchElementException() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
|
||||
.forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
|
||||
|
||||
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
assertThrows(NoSuchElementException.class, () -> PGPainless.getInstance().modify(secretKeys)
|
||||
.revokeUserId("invalid@user.id", protector));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidRevocationReasonThrowsIllegalArgumentException() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE);
|
||||
.forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
assertThrows(IllegalArgumentException.class, () -> PGPainless.getInstance().modify(secretKeys)
|
||||
.revokeUserId("cryptie@encrypted.key", protector,
|
||||
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED)
|
||||
.withDescription("This is not a valid certification revocation reason.")));
|
||||
|
|
|
@ -16,8 +16,7 @@ import java.util.List;
|
|||
import org.bouncycastle.bcpg.KeyIdentifier;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -39,14 +38,15 @@ public class AddSubKeyTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testAddSubKey()
|
||||
throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
|
||||
List<KeyIdentifier> keyIdentifiersBefore = new ArrayList<>();
|
||||
for (Iterator<PGPPublicKey> it = secretKeys.getPublicKeys(); it.hasNext(); ) {
|
||||
for (Iterator<PGPPublicKey> it = secretKeys.getPGPSecretKeyRing().getPublicKeys(); it.hasNext(); ) {
|
||||
keyIdentifiersBefore.add(it.next().getKeyIdentifier());
|
||||
}
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addSubKey(
|
||||
KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256), KeyFlag.SIGN_DATA).build(),
|
||||
Passphrase.fromPassword("subKeyPassphrase"),
|
||||
|
@ -54,7 +54,7 @@ public class AddSubKeyTest {
|
|||
.done();
|
||||
|
||||
List<KeyIdentifier> keyIdentifiersAfter = new ArrayList<>();
|
||||
for (Iterator<PGPPublicKey> it = secretKeys.getPublicKeys(); it.hasNext(); ) {
|
||||
for (Iterator<PGPPublicKey> it = secretKeys.getPGPSecretKeyRing().getPublicKeys(); it.hasNext(); ) {
|
||||
keyIdentifiersAfter.add(it.next().getKeyIdentifier());
|
||||
}
|
||||
assertNotEquals(keyIdentifiersAfter, keyIdentifiersBefore);
|
||||
|
@ -62,12 +62,12 @@ public class AddSubKeyTest {
|
|||
keyIdentifiersAfter.removeAll(keyIdentifiersBefore);
|
||||
KeyIdentifier subKeyIdentifier = keyIdentifiersAfter.get(0);
|
||||
|
||||
PGPSecretKey subKey = secretKeys.getSecretKey(subKeyIdentifier);
|
||||
OpenPGPKey.OpenPGPSecretKey subKey = secretKeys.getSecretKey(subKeyIdentifier);
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith(
|
||||
Passphrase.fromPassword("subKeyPassphrase"), secretKeys);
|
||||
UnlockSecretKey.unlockSecretKey(subKey, protector);
|
||||
|
||||
KeyRingInfo info = new KeyRingInfo(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertEquals(Collections.singletonList(KeyFlag.SIGN_DATA), info.getKeyFlagsOf(subKeyIdentifier));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@ import java.util.List;
|
|||
|
||||
import org.bouncycastle.bcpg.sig.NotationData;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -38,11 +38,11 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
|
|||
|
||||
@Test
|
||||
public void bindEncryptionSubkeyAndModifyBindingSignatureHashedSubpackets() {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>")
|
||||
.getPGPSecretKeyRing();
|
||||
KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys);
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>");
|
||||
KeyRingInfo before = api.inspect(secretKeys);
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysBefore = before.getSigningSubkeys();
|
||||
|
||||
PGPKeyPair secretSubkey = KeyRingBuilder.generateKeyPair(
|
||||
|
@ -50,7 +50,7 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
|
|||
OpenPGPKeyVersion.v4);
|
||||
|
||||
long secondsUntilExpiration = 1000;
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addSubKey(secretSubkey, new SelfSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
|
||||
|
@ -60,7 +60,7 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
|
|||
}, SecretKeyRingProtector.unprotectedKeys(), protector, KeyFlag.SIGN_DATA)
|
||||
.done();
|
||||
|
||||
KeyRingInfo after = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo after = api.inspect(secretKeys);
|
||||
List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysAfter = after.getSigningSubkeys();
|
||||
signingKeysAfter.removeAll(signingKeysBefore);
|
||||
assertFalse(signingKeysAfter.isEmpty());
|
||||
|
|
|
@ -37,31 +37,31 @@ public class AddUserIdTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void addUserIdToExistingKeyRing()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le");
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
Iterator<String> userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("alice@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("rabb1th0le"));
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("cheshirecat@wonderland.lit", protector)
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(secretKeys);
|
||||
userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("alice@wonderland.lit", userIds.next());
|
||||
assertEquals("cheshirecat@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeUserId("cheshirecat@wonderland.lit", protector)
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(secretKeys);
|
||||
userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("alice@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
|
@ -96,20 +96,21 @@ public class AddUserIdTest {
|
|||
"=bk4o\r\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||||
|
||||
OpenPGPKey key = PGPainless.getInstance().readKey().parseKey(ARMORED_PRIVATE_KEY);
|
||||
PGPSecretKeyRing secretKeys = key.getPGPSecretKeyRing();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
|
||||
OpenPGPKey key = api.readKey().parseKey(ARMORED_PRIVATE_KEY);
|
||||
KeyRingInfo info = api.inspect(key);
|
||||
Iterator<String> userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("<user@example.com>", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
|
||||
SecretKeyRingProtector protector = new UnprotectedKeysProtector();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
key = api.modify(key)
|
||||
.revokeUserId("<user@example.com>", protector)
|
||||
.addUserId("cheshirecat@wonderland.lit", protector)
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys);
|
||||
info = api.inspect(key);
|
||||
userIds = info.getValidUserIds().iterator();
|
||||
assertEquals("cheshirecat@wonderland.lit", userIds.next());
|
||||
assertFalse(userIds.hasNext());
|
||||
|
@ -118,17 +119,17 @@ public class AddUserIdTest {
|
|||
@Test
|
||||
public void addNewPrimaryUserIdTest() {
|
||||
Date now = new Date();
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice");
|
||||
UserId bob = UserId.builder().withName("Bob").noEmail().noComment().build();
|
||||
|
||||
assertNotEquals("Bob", PGPainless.inspectKeyRing(secretKeys).getPrimaryUserId());
|
||||
assertNotEquals("Bob", api.inspect(secretKeys).getPrimaryUserId());
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, DateExtensionsKt.plusSeconds(now, 1))
|
||||
secretKeys = api.modify(secretKeys, DateExtensionsKt.plusSeconds(now, 1))
|
||||
.addPrimaryUserId(bob, SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
assertEquals("Bob", PGPainless.inspectKeyRing(secretKeys, DateExtensionsKt.plusSeconds(now, 2)).getPrimaryUserId());
|
||||
assertEquals("Bob", api.inspect(secretKeys, DateExtensionsKt.plusSeconds(now, 2)).getPrimaryUserId());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ package org.pgpainless.key.modification;
|
|||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -138,7 +138,8 @@ public class ChangeExpirationOnKeyWithDifferentSignatureTypesTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void setExpirationDate_keyHasSigClass10()
|
||||
throws IOException {
|
||||
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(keyWithGenericCertification);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey keys = api.readKey().parseKey(keyWithGenericCertification);
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
executeTestForKeys(keys, protector);
|
||||
}
|
||||
|
@ -147,20 +148,23 @@ public class ChangeExpirationOnKeyWithDifferentSignatureTypesTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void setExpirationDate_keyHasSigClass12()
|
||||
throws IOException {
|
||||
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(keyWithCasualCertification);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey keys = api.readKey().parseKey(keyWithCasualCertification);
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
executeTestForKeys(keys, protector);
|
||||
}
|
||||
|
||||
private void executeTestForKeys(PGPSecretKeyRing keys, SecretKeyRingProtector protector) {
|
||||
private void executeTestForKeys(OpenPGPKey keys, SecretKeyRingProtector protector) {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 14);
|
||||
// round date for test stability
|
||||
expirationDate = DateUtil.toSecondsPrecision(expirationDate);
|
||||
|
||||
PGPSecretKeyRing modded = PGPainless.modifyKeyRing(keys)
|
||||
OpenPGPKey modded = api.modify(keys)
|
||||
.setExpirationDate(expirationDate, protector)
|
||||
.done();
|
||||
|
||||
JUtils.assertDateEquals(expirationDate, PGPainless.inspectKeyRing(modded).getPrimaryKeyExpirationDate());
|
||||
JUtils.assertDateEquals(expirationDate, api.inspect(modded).getPrimaryKeyExpirationDate());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.util.Calendar;
|
|||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -35,27 +35,28 @@ public class ChangeExpirationTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void setExpirationDateAndThenUnsetIt_OnPrimaryKey()
|
||||
throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo sInfo = api.inspect(secretKeys);
|
||||
|
||||
assertNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
|
||||
|
||||
Date now = new Date();
|
||||
Date date = DateUtil.parseUTCDate("2020-11-27 16:10:32 UTC");
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDate(date, new UnprotectedKeysProtector()).done();
|
||||
sInfo = PGPainless.inspectKeyRing(secretKeys);
|
||||
sInfo = api.inspect(secretKeys);
|
||||
assertNotNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
assertEquals(date.getTime(), sInfo.getPrimaryKeyExpirationDate().getTime());
|
||||
// subkey unchanged
|
||||
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
|
||||
|
||||
Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.setExpirationDate(null, new UnprotectedKeysProtector()).done();
|
||||
|
||||
sInfo = PGPainless.inspectKeyRing(secretKeys, t1);
|
||||
sInfo = api.inspect(secretKeys, t1);
|
||||
assertNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
|
||||
}
|
||||
|
@ -64,9 +65,9 @@ public class ChangeExpirationTest {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void setExpirationDateAndThenUnsetIt_OnSubkey()
|
||||
throws PGPException, IOException {
|
||||
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
KeyRingInfo sInfo = api.inspect(secretKeys);
|
||||
|
||||
assertNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
|
||||
|
@ -76,42 +77,43 @@ public class ChangeExpirationTest {
|
|||
calendar.add(Calendar.DATE, 5);
|
||||
Date expiration = calendar.getTime(); // in 5 days
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDate(expiration, new UnprotectedKeysProtector()).done();
|
||||
sInfo = PGPainless.inspectKeyRing(secretKeys);
|
||||
sInfo = api.inspect(secretKeys);
|
||||
assertNotNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
JUtils.assertDateEquals(expiration, sInfo.getPrimaryKeyExpirationDate());
|
||||
|
||||
Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.setExpirationDate(null, new UnprotectedKeysProtector()).done();
|
||||
|
||||
sInfo = PGPainless.inspectKeyRing(secretKeys, t1);
|
||||
sInfo = api.inspect(secretKeys, t1);
|
||||
assertNull(sInfo.getPrimaryKeyExpirationDate());
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testExtremeExpirationDates() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
// seconds from 2021 to 2199 will overflow 32bit integers
|
||||
Date farAwayExpiration = DateUtil.parseUTCDate("2199-01-01 00:00:00 UTC");
|
||||
|
||||
final PGPSecretKeyRing finalKeys = secretKeys;
|
||||
final OpenPGPKey finalKeys = secretKeys;
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
PGPainless.modifyKeyRing(finalKeys)
|
||||
api.modify(finalKeys)
|
||||
.setExpirationDate(farAwayExpiration, protector)
|
||||
.done());
|
||||
|
||||
Date notSoFarAwayExpiration = DateUtil.parseUTCDate("2100-01-01 00:00:00 UTC");
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDate(notSoFarAwayExpiration, protector)
|
||||
.done();
|
||||
|
||||
Date actualExpiration = PGPainless.inspectKeyRing(secretKeys)
|
||||
Date actualExpiration = api.inspect(secretKeys)
|
||||
.getPrimaryKeyExpirationDate();
|
||||
JUtils.assertDateEquals(notSoFarAwayExpiration, actualExpiration);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
package org.pgpainless.key.modification;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
|
@ -26,13 +26,14 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
@Test
|
||||
public void generateA_primaryB_revokeA_cantSecondaryA()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("A")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("A");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
Date now = new Date();
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys, now);
|
||||
KeyRingInfo info = api.inspect(secretKeys, now);
|
||||
assertFalse(info.isHardRevoked("A"));
|
||||
assertFalse(info.isHardRevoked("B"));
|
||||
assertIsPrimaryUserId("A", info);
|
||||
|
@ -41,10 +42,10 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
|
||||
// One hour later
|
||||
Date oneHourLater = new Date(now.getTime() + millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, oneHourLater)
|
||||
secretKeys = api.modify(secretKeys, oneHourLater)
|
||||
.addPrimaryUserId("B", protector)
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(secretKeys, oneHourLater);
|
||||
info = api.inspect(secretKeys, oneHourLater);
|
||||
|
||||
assertIsPrimaryUserId("B", info);
|
||||
assertIsNotPrimaryUserId("A", info);
|
||||
|
@ -52,10 +53,10 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
// Two hours later
|
||||
Date twoHoursLater = new Date(now.getTime() + 2 * millisInHour);
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, twoHoursLater)
|
||||
secretKeys = api.modify(secretKeys, twoHoursLater)
|
||||
.revokeUserId("A", protector) // hard revoke A
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(secretKeys, twoHoursLater);
|
||||
info = api.inspect(secretKeys, twoHoursLater);
|
||||
|
||||
assertTrue(info.isHardRevoked("A"));
|
||||
assertFalse(info.isHardRevoked("B"));
|
||||
|
@ -65,71 +66,71 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
// Three hours later
|
||||
Date threeHoursLater = new Date(now.getTime() + 3 * millisInHour);
|
||||
|
||||
PGPSecretKeyRing finalSecretKeys = secretKeys;
|
||||
OpenPGPKey finalSecretKeys = secretKeys;
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
PGPainless.modifyKeyRing(finalSecretKeys, threeHoursLater).addUserId("A", protector));
|
||||
api.modify(finalSecretKeys, threeHoursLater).addUserId("A", protector));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateA_primaryExpire_isExpired() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("A")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("A");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertIsPrimaryUserId("A", info);
|
||||
|
||||
Date now = new Date();
|
||||
Date later = new Date(now.getTime() + millisInHour);
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, now)
|
||||
secretKeys = api.modify(secretKeys, now)
|
||||
.setExpirationDate(later, protector) // expire the whole key
|
||||
.done();
|
||||
|
||||
Date evenLater = new Date(now.getTime() + 2 * millisInHour);
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, evenLater);
|
||||
info = api.inspect(secretKeys, evenLater);
|
||||
assertFalse(info.isUserIdValid("A")); // is expired by now
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateA_primaryB_primaryExpire_bIsStillPrimary() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("A")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("A");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
Date now = new Date();
|
||||
// Generate key with primary user-id A
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertIsPrimaryUserId("A", info);
|
||||
|
||||
// later set primary user-id to B
|
||||
Date t1 = new Date(now.getTime() + millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.addPrimaryUserId("B", protector)
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t1);
|
||||
info = api.inspect(secretKeys, t1);
|
||||
assertIsPrimaryUserId("B", info);
|
||||
assertIsNotPrimaryUserId("A", info);
|
||||
|
||||
// Even later expire the whole key
|
||||
Date t2 = new Date(now.getTime() + 2 * millisInHour);
|
||||
Date expiration = new Date(now.getTime() + 10 * millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2)
|
||||
secretKeys = api.modify(secretKeys, t2)
|
||||
.setExpirationDate(expiration, protector) // expire the whole key in 1 hour
|
||||
.done();
|
||||
|
||||
Date t3 = new Date(now.getTime() + 3 * millisInHour);
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t3);
|
||||
info = api.inspect(secretKeys, t3);
|
||||
assertIsValid("A", info);
|
||||
assertIsValid("B", info);
|
||||
assertIsPrimaryUserId("B", info);
|
||||
assertIsNotPrimaryUserId("A", info);
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, expiration);
|
||||
info = api.inspect(secretKeys, expiration);
|
||||
assertIsPrimaryUserId("B", info); // B is still primary, even though
|
||||
assertFalse(info.isUserIdValid("A")); // key is expired by now
|
||||
assertFalse(info.isUserIdValid("B"));
|
||||
|
@ -137,23 +138,23 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
|
||||
@Test
|
||||
public void generateA_expire_certify() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("A")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("A");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
Date now = new Date();
|
||||
Date t1 = new Date(now.getTime() + millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, now)
|
||||
secretKeys = api.modify(secretKeys, now)
|
||||
.setExpirationDate(t1, protector)
|
||||
.done();
|
||||
|
||||
Date t2 = new Date(now.getTime() + 2 * millisInHour);
|
||||
Date t4 = new Date(now.getTime() + 4 * millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2)
|
||||
secretKeys = api.modify(secretKeys, t2)
|
||||
.setExpirationDate(t4, protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertIsValid("A", info);
|
||||
assertIsPrimaryUserId("A", info);
|
||||
}
|
||||
|
@ -161,28 +162,28 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
@Test
|
||||
public void generateA_expire_primaryB_expire_isPrimaryB()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("A")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("A");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
Date now = new Date();
|
||||
Date t1 = new Date(now.getTime() + millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.setExpirationDate(t1, protector)
|
||||
.done();
|
||||
|
||||
Date t2 = new Date(now.getTime() + 2 * millisInHour);
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys, t2);
|
||||
KeyRingInfo info = api.inspect(secretKeys, t2);
|
||||
|
||||
assertIsPrimaryUserId("A", info);
|
||||
assertIsNotValid("A", info); // A is expired
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2)
|
||||
secretKeys = api.modify(secretKeys, t2)
|
||||
.addPrimaryUserId("B", protector)
|
||||
.done();
|
||||
|
||||
Date t3 = new Date(now.getTime() + 3 * millisInHour);
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t3);
|
||||
info = api.inspect(secretKeys, t3);
|
||||
|
||||
assertIsPrimaryUserId("B", info);
|
||||
assertIsNotValid("B", info); // A and B are still expired
|
||||
|
@ -190,19 +191,19 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
|
|||
|
||||
Date t4 = new Date(now.getTime() + 4 * millisInHour);
|
||||
Date t5 = new Date(now.getTime() + 5 * millisInHour);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t3)
|
||||
secretKeys = api.modify(secretKeys, t3)
|
||||
.setExpirationDate(t5, protector)
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t4);
|
||||
info = api.inspect(secretKeys, t4);
|
||||
assertIsValid("B", info);
|
||||
assertIsValid("A", info); // A got re-validated when changing exp date
|
||||
assertIsPrimaryUserId("B", info);
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t4)
|
||||
secretKeys = api.modify(secretKeys, t4)
|
||||
.addUserId("A", protector) // re-certify A as non-primary user-id
|
||||
.done();
|
||||
info = PGPainless.inspectKeyRing(secretKeys, t4);
|
||||
info = api.inspect(secretKeys, t4);
|
||||
|
||||
assertIsValid("B", info);
|
||||
assertIsValid("A", info);
|
||||
|
|
|
@ -15,8 +15,8 @@ import java.util.Iterator;
|
|||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
|
@ -35,8 +35,8 @@ import org.pgpainless.util.Passphrase;
|
|||
|
||||
public class ChangeSecretKeyRingPassphraseTest {
|
||||
|
||||
private final PGPSecretKeyRing keyRing = PGPainless.generateKeyRing().simpleEcKeyRing("password@encryp.ted", "weakPassphrase")
|
||||
.getPGPSecretKeyRing();
|
||||
private final OpenPGPKey keyRing = PGPainless.getInstance()
|
||||
.generateKey().simpleEcKeyRing("password@encryp.ted", "weakPassphrase");
|
||||
|
||||
public ChangeSecretKeyRingPassphraseTest() {
|
||||
}
|
||||
|
@ -44,66 +44,64 @@ public class ChangeSecretKeyRingPassphraseTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void changePassphraseOfWholeKeyRingTest() throws PGPException {
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.modify(keyRing)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase"))
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("1337p455phr453"))
|
||||
.done();
|
||||
|
||||
PGPSecretKeyRing changedPassphraseKeyRing = secretKeys;
|
||||
|
||||
assertEquals(KeyRingProtectionSettings.secureDefaultSettings().getEncryptionAlgorithm().getAlgorithmId(),
|
||||
changedPassphraseKeyRing.getSecretKey().getKeyEncryptionAlgorithm());
|
||||
secretKeys.getPGPSecretKeyRing().getSecretKey().getKeyEncryptionAlgorithm());
|
||||
|
||||
assertThrows(PGPException.class, () ->
|
||||
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.emptyPassphrase()),
|
||||
signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.emptyPassphrase()),
|
||||
"Unlocking secret key ring with empty passphrase MUST fail.");
|
||||
|
||||
assertThrows(PGPException.class, () ->
|
||||
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.fromPassword("weakPassphrase")),
|
||||
signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.fromPassword("weakPassphrase")),
|
||||
"Unlocking secret key ring with old passphrase MUST fail.");
|
||||
|
||||
assertDoesNotThrow(() -> signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.fromPassword("1337p455phr453")),
|
||||
assertDoesNotThrow(() -> signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.fromPassword("1337p455phr453")),
|
||||
"Unlocking the secret key ring with the new passphrase MUST succeed.");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void changePassphraseOfWholeKeyRingToEmptyPassphrase() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
|
||||
OpenPGPKey changedPassphraseKeyRing = api.modify(keyRing)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase"))
|
||||
.withSecureDefaultSettings()
|
||||
.toNoPassphrase()
|
||||
.done();
|
||||
|
||||
PGPSecretKeyRing changedPassphraseKeyRing = secretKeys;
|
||||
|
||||
assertEquals(SymmetricKeyAlgorithm.NULL.getAlgorithmId(),
|
||||
changedPassphraseKeyRing.getSecretKey().getKeyEncryptionAlgorithm());
|
||||
changedPassphraseKeyRing.getPGPSecretKeyRing().getSecretKey().getKeyEncryptionAlgorithm());
|
||||
|
||||
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.emptyPassphrase());
|
||||
signDummyMessageWithKeysAndPassphrase(api, changedPassphraseKeyRing, Passphrase.emptyPassphrase());
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void changePassphraseOfSingleSubkeyToNewPassphrase() throws PGPException {
|
||||
|
||||
Iterator<PGPSecretKey> keys = keyRing.getSecretKeys();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
Iterator<PGPSecretKey> keys = keyRing.getPGPSecretKeyRing().getSecretKeys();
|
||||
PGPSecretKey primaryKey = keys.next();
|
||||
PGPSecretKey subKey = keys.next();
|
||||
|
||||
extractPrivateKey(primaryKey, Passphrase.fromPassword("weakPassphrase"));
|
||||
extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase"));
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
|
||||
OpenPGPKey secretKeys = api.modify(keyRing)
|
||||
.changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyIdentifier(),
|
||||
Passphrase.fromPassword("weakPassphrase"))
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase"))
|
||||
.done();
|
||||
|
||||
keys = secretKeys.getSecretKeys();
|
||||
keys = secretKeys.getPGPSecretKeyRing().getSecretKeys();
|
||||
primaryKey = keys.next();
|
||||
subKey = keys.next();
|
||||
|
||||
|
@ -124,18 +122,18 @@ public class ChangeSecretKeyRingPassphraseTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void changePassphraseOfSingleSubkeyToEmptyPassphrase() throws PGPException {
|
||||
|
||||
Iterator<PGPSecretKey> keys = keyRing.getSecretKeys();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
Iterator<PGPSecretKey> keys = keyRing.getPGPSecretKeyRing().getSecretKeys();
|
||||
PGPSecretKey primaryKey = keys.next();
|
||||
PGPSecretKey subKey = keys.next();
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing)
|
||||
OpenPGPKey secretKeys = api.modify(keyRing)
|
||||
.changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase"))
|
||||
.withSecureDefaultSettings()
|
||||
.toNoPassphrase()
|
||||
.done();
|
||||
|
||||
keys = secretKeys.getSecretKeys();
|
||||
keys = secretKeys.getPGPSecretKeyRing().getSecretKeys();
|
||||
primaryKey = keys.next();
|
||||
subKey = keys.next();
|
||||
|
||||
|
@ -176,13 +174,13 @@ public class ChangeSecretKeyRingPassphraseTest {
|
|||
UnlockSecretKey.unlockSecretKey(secretKey, decryptor);
|
||||
}
|
||||
|
||||
private void signDummyMessageWithKeysAndPassphrase(PGPSecretKeyRing keyRing, Passphrase passphrase) throws IOException, PGPException {
|
||||
private void signDummyMessageWithKeysAndPassphrase(PGPainless api, OpenPGPKey key, Passphrase passphrase) throws IOException, PGPException {
|
||||
String dummyMessage = "dummy";
|
||||
ByteArrayOutputStream dummy = new ByteArrayOutputStream();
|
||||
EncryptionStream stream = PGPainless.encryptAndOrSign().onOutputStream(dummy)
|
||||
EncryptionStream stream = api.generateMessage().onOutputStream(dummy)
|
||||
.withOptions(ProducerOptions.sign(SigningOptions.get()
|
||||
.addInlineSignature(PasswordBasedSecretKeyRingProtector.forKey(keyRing, passphrase),
|
||||
keyRing, DocumentSignatureType.BINARY_DOCUMENT)));
|
||||
.addInlineSignature(PasswordBasedSecretKeyRingProtector.forKey(key, passphrase),
|
||||
key, DocumentSignatureType.BINARY_DOCUMENT)));
|
||||
|
||||
Streams.pipeAll(new ByteArrayInputStream(dummyMessage.getBytes()), stream);
|
||||
stream.close();
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
package org.pgpainless.key.modification;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -25,26 +25,27 @@ public class ChangeSubkeyExpirationTimeTest {
|
|||
|
||||
@Test
|
||||
public void changeExpirationTimeOfSubkey() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
Date now = secretKeys.getPublicKey().getCreationTime();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
Date now = secretKeys.getPrimaryKey().getCreationTime();
|
||||
Date inAnHour = new Date(now.getTime() + 1000 * 60 * 60);
|
||||
OpenPGPCertificate.OpenPGPComponentKey encryptionKey = PGPainless.inspectKeyRing(secretKeys)
|
||||
OpenPGPCertificate.OpenPGPComponentKey encryptionKey = api.inspect(secretKeys)
|
||||
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0);
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDateOfSubkey(
|
||||
inAnHour,
|
||||
encryptionKey.getKeyIdentifier().getKeyId(),
|
||||
encryptionKey.getKeyIdentifier(),
|
||||
SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
JUtils.assertDateEquals(inAnHour, PGPainless.inspectKeyRing(secretKeys)
|
||||
JUtils.assertDateEquals(inAnHour, api.inspect(secretKeys)
|
||||
.getSubkeyExpirationDate(OpenPgpFingerprint.of(encryptionKey.getPGPPublicKey())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeExpirationTimeOfExpiredSubkey() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(
|
||||
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||
"Version: PGPainless\n" +
|
||||
"Comment: CA52 4D5D E3D8 9CD9 105B BA45 3761 076B C6B5 3000\n" +
|
||||
|
@ -79,13 +80,13 @@ public class ChangeSubkeyExpirationTimeTest {
|
|||
OpenPgpFingerprint encryptionSubkey = new OpenPgpV4Fingerprint("2E541354A23C9943375EC27A3EF133ED8720D636");
|
||||
JUtils.assertDateEquals(
|
||||
DateUtil.parseUTCDate("2023-12-07 16:29:46 UTC"),
|
||||
PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
|
||||
api.inspect(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
|
||||
|
||||
// re-validate the subkey by setting its expiry to null (no expiry)
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
.setExpirationDateOfSubkey(null, encryptionSubkey.getKeyId(), SecretKeyRingProtector.unprotectedKeys())
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDateOfSubkey(null, encryptionSubkey.getKeyIdentifier(), SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
assertNull(PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
|
||||
assertNull(api.inspect(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -73,9 +73,10 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
|
|||
|
||||
@Test
|
||||
public void manualReplaceUserIdWithFixedVersionDoesNotHinderEncryptionCapability() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
PGPSecretKeyRing modified = PGPainless.modifyKeyRing(secretKeys)
|
||||
OpenPGPKey modified = api.modify(secretKeys)
|
||||
.addUserId(userIdAfter, new SelfSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
|
||||
|
@ -85,8 +86,8 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
|
|||
.removeUserId(userIdBefore, protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo after = PGPainless.inspectKeyRing(modified);
|
||||
KeyRingInfo before = api.inspect(secretKeys);
|
||||
KeyRingInfo after = api.inspect(modified);
|
||||
|
||||
assertEquals(userIdBefore, before.getPrimaryUserId());
|
||||
assertEquals(userIdAfter, after.getPrimaryUserId());
|
||||
|
@ -104,34 +105,38 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
|
|||
|
||||
@Test
|
||||
public void testReplaceUserId_missingOldUserIdThrows() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY);
|
||||
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
|
||||
assertThrows(NoSuchElementException.class, () -> api.modify(secretKeys)
|
||||
.replaceUserId("missing", userIdAfter, SecretKeyRingProtector.unprotectedKeys()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUserId_emptyOldUserIdThrows() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY);
|
||||
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
|
||||
assertThrows(IllegalArgumentException.class, () -> api.modify(secretKeys)
|
||||
.replaceUserId(" ", userIdAfter, SecretKeyRingProtector.unprotectedKeys()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceUserId_emptyNewUserIdThrows() throws IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY);
|
||||
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
|
||||
assertThrows(IllegalArgumentException.class, () -> api.modify(secretKeys)
|
||||
.replaceUserId(userIdBefore, " ", SecretKeyRingProtector.unprotectedKeys()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceImplicitUserIdDoesNotBreakStuff() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
|
||||
|
||||
PGPSecretKeyRing edited = PGPainless.modifyKeyRing(secretKeys)
|
||||
OpenPGPKey edited = api.modify(secretKeys)
|
||||
.replaceUserId(userIdBefore, userIdAfter, SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(edited);
|
||||
KeyRingInfo info = api.inspect(edited);
|
||||
assertTrue(info.isUserIdValid(userIdAfter));
|
||||
assertEquals(userIdAfter, info.getPrimaryUserId());
|
||||
|
||||
|
@ -139,10 +144,10 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
|
|||
assertNotNull(latestCertification);
|
||||
assertTrue(latestCertification.getHashedSubPackets().isPrimaryUserID());
|
||||
|
||||
PGPPublicKeyRing cert = PGPainless.extractCertificate(edited);
|
||||
OpenPGPCertificate cert = edited.toCertificate();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
|
||||
EncryptionStream encryptionStream = api.generateMessage()
|
||||
.onOutputStream(out)
|
||||
.withOptions(ProducerOptions.encrypt(EncryptionOptions.get()
|
||||
.addRecipient(cert)));
|
||||
|
@ -151,7 +156,7 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
|
|||
encryptionStream.close();
|
||||
|
||||
EncryptionResult result = encryptionStream.getResult();
|
||||
assertTrue(result.isEncryptedFor(cert));
|
||||
assertTrue(result.isEncryptedFor(cert.getPGPPublicKeyRing()));
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||
ByteArrayOutputStream plain = new ByteArrayOutputStream();
|
||||
|
|
|
@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.util.Passphrase;
|
||||
|
@ -166,17 +166,18 @@ public class GnuDummyS2KChangePassphraseTest {
|
|||
|
||||
@Test
|
||||
public void testChangePassphraseToNoPassphraseIgnoresGnuDummyS2KKeys() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(KEY_WITH_GNU_DUMMY_S2K_PRIMARY_KEY);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKey = api.readKey().parseKey(KEY_WITH_GNU_DUMMY_S2K_PRIMARY_KEY);
|
||||
|
||||
assertFalse(PGPainless.inspectKeyRing(secretKey).isFullyDecrypted());
|
||||
assertFalse(api.inspect(secretKey).isFullyDecrypted());
|
||||
|
||||
secretKey = PGPainless.modifyKeyRing(secretKey)
|
||||
secretKey = api.modify(secretKey)
|
||||
.changePassphraseFromOldPassphrase(passphrase)
|
||||
.withSecureDefaultSettings()
|
||||
.toNoPassphrase()
|
||||
.done();
|
||||
|
||||
assertTrue(PGPainless.inspectKeyRing(secretKey).isFullyDecrypted());
|
||||
assertTrue(api.inspect(secretKey).isFullyDecrypted());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -26,11 +26,11 @@ public class OldSignatureSubpacketsArePreservedOnNewSigTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void verifyOldSignatureSubpacketsArePreservedOnNewExpirationDateSig() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing("Alice <alice@wonderland.lit>")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.simpleEcKeyRing("Alice <alice@wonderland.lit>");
|
||||
|
||||
PGPSignature oldSignature = PGPainless.inspectKeyRing(secretKeys).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
|
||||
PGPSignature oldSignature = api.inspect(secretKeys).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
|
||||
assertNotNull(oldSignature);
|
||||
PGPSignatureSubpacketVector oldPackets = oldSignature.getHashedSubPackets();
|
||||
|
||||
|
@ -40,10 +40,10 @@ public class OldSignatureSubpacketsArePreservedOnNewSigTest {
|
|||
Date t1 = new Date(now.getTime() + millisInHour);
|
||||
Date expiration = new Date(now.getTime() + 5 * 24 * millisInHour); // in 5 days
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1)
|
||||
secretKeys = api.modify(secretKeys, t1)
|
||||
.setExpirationDate(expiration, new UnprotectedKeysProtector())
|
||||
.done();
|
||||
PGPSignature newSignature = PGPainless.inspectKeyRing(secretKeys, t1).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
|
||||
PGPSignature newSignature = api.inspect(secretKeys, t1).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
|
||||
assertNotNull(newSignature);
|
||||
PGPSignatureSubpacketVector newPackets = newSignature.getHashedSubPackets();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
|||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.EncryptionPurpose;
|
||||
|
@ -28,31 +28,31 @@ public class RefuseToAddWeakSubkeyTest {
|
|||
|
||||
@Test
|
||||
public void testEditorRefusesToAddWeakSubkey() {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
// ensure default policy is set
|
||||
Policy oldPolicy = PGPainless.getPolicy();
|
||||
Policy oldPolicy = api.getAlgorithmPolicy();
|
||||
Policy adjusted = oldPolicy.copy().withPublicKeyAlgorithmPolicy(
|
||||
Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy()
|
||||
).build();
|
||||
PGPainless.getInstance().setAlgorithmPolicy(adjusted);
|
||||
api.setAlgorithmPolicy(adjusted);
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys);
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice");
|
||||
SecretKeyRingEditorInterface editor = api.modify(secretKeys);
|
||||
KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS).build();
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys()));
|
||||
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy);
|
||||
api.setAlgorithmPolicy(oldPolicy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEditorAllowsToAddWeakSubkeyIfCompliesToPublicKeyAlgorithmPolicy() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice");
|
||||
|
||||
Policy oldPolicy = PGPainless.getPolicy();
|
||||
Policy oldPolicy = api.getAlgorithmPolicy();
|
||||
|
||||
// set weak policy
|
||||
Map<PublicKeyAlgorithm, Integer> minimalBitStrengths = new EnumMap<>(PublicKeyAlgorithm.class);
|
||||
|
@ -75,11 +75,11 @@ public class RefuseToAddWeakSubkeyTest {
|
|||
minimalBitStrengths.put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000);
|
||||
// §7.2.2
|
||||
minimalBitStrengths.put(PublicKeyAlgorithm.ECDH, 250);
|
||||
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy.copy()
|
||||
api.setAlgorithmPolicy(oldPolicy.copy()
|
||||
.withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(minimalBitStrengths))
|
||||
.build());
|
||||
|
||||
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys);
|
||||
SecretKeyRingEditorInterface editor = api.modify(secretKeys);
|
||||
KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS)
|
||||
.setKeyCreationDate(editor.getReferenceTime()) // The key gets created after we instantiate the editor.
|
||||
.build();
|
||||
|
@ -87,9 +87,9 @@ public class RefuseToAddWeakSubkeyTest {
|
|||
secretKeys = editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
assertEquals(2, PGPainless.inspectKeyRing(secretKeys).getEncryptionSubkeys(EncryptionPurpose.ANY).size());
|
||||
assertEquals(2, api.inspect(secretKeys).getEncryptionSubkeys(EncryptionPurpose.ANY).size());
|
||||
|
||||
// reset default policy
|
||||
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy);
|
||||
api.setAlgorithmPolicy(oldPolicy);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,10 @@ import java.io.IOException;
|
|||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.TestKeys;
|
||||
|
@ -30,9 +31,10 @@ public class RevocationCertificateTest {
|
|||
|
||||
@Test
|
||||
public void createRevocationCertificateTest() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
|
||||
PGPSignature revocation = PGPainless.modifyKeyRing(secretKeys)
|
||||
OpenPGPSignature revocation = api.modify(secretKeys)
|
||||
.createRevocation(SecretKeyRingProtector.unprotectedKeys(),
|
||||
RevocationAttributes.createKeyRevocation()
|
||||
.withReason(RevocationAttributes.Reason.KEY_RETIRED)
|
||||
|
@ -40,66 +42,68 @@ public class RevocationCertificateTest {
|
|||
|
||||
assertNotNull(revocation);
|
||||
|
||||
assertTrue(PGPainless.inspectKeyRing(secretKeys).isKeyValidlyBound(secretKeys.getPublicKey().getKeyID()));
|
||||
assertTrue(api.inspect(secretKeys).isKeyValidlyBound(secretKeys.getKeyIdentifier()));
|
||||
|
||||
// merge key and revocation certificate
|
||||
PGPSecretKeyRing revokedKey = KeyRingUtils.keysPlusSecretKey(
|
||||
secretKeys,
|
||||
KeyRingUtils.secretKeyPlusSignature(secretKeys.getSecretKey(), revocation));
|
||||
secretKeys.getPGPSecretKeyRing(),
|
||||
KeyRingUtils.secretKeyPlusSignature(secretKeys.getPrimarySecretKey().getPGPSecretKey(), revocation.getSignature()));
|
||||
|
||||
assertFalse(PGPainless.inspectKeyRing(revokedKey).isKeyValidlyBound(secretKeys.getPublicKey().getKeyID()));
|
||||
assertFalse(api.inspect(api.toKey(revokedKey)).isKeyValidlyBound(secretKeys.getKeyIdentifier()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMinimalRevocationCertificateTest() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
|
||||
PGPPublicKeyRing minimalRevocationCert = PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate(
|
||||
OpenPGPCertificate minimalRevocationCert = api.modify(secretKeys).createMinimalRevocationCertificate(
|
||||
SecretKeyRingProtector.unprotectedKeys(),
|
||||
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription());
|
||||
|
||||
assertEquals(1, minimalRevocationCert.size());
|
||||
PGPPublicKey key = minimalRevocationCert.getPublicKey();
|
||||
assertEquals(secretKeys.getPublicKey().getKeyID(), key.getKeyID());
|
||||
assertEquals(1, minimalRevocationCert.getPGPKeyRing().size());
|
||||
PGPPublicKey key = minimalRevocationCert.getPrimaryKey().getPGPPublicKey();
|
||||
assertEquals(secretKeys.getKeyIdentifier(), key.getKeyIdentifier());
|
||||
assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size());
|
||||
assertFalse(key.getUserIDs().hasNext());
|
||||
assertFalse(key.getUserAttributes().hasNext());
|
||||
assertNull(key.getTrustData());
|
||||
|
||||
PGPPublicKeyRing originalCert = PGPainless.extractCertificate(secretKeys);
|
||||
PGPPublicKeyRing mergedCert = PGPainless.mergeCertificate(originalCert, minimalRevocationCert);
|
||||
OpenPGPCertificate originalCert = secretKeys.toCertificate();
|
||||
OpenPGPCertificate mergedCert = api.mergeCertificate(originalCert, minimalRevocationCert);
|
||||
|
||||
assertTrue(PGPainless.inspectKeyRing(mergedCert).getRevocationState().isSoftRevocation());
|
||||
assertTrue(api.inspect(mergedCert).getRevocationState().isSoftRevocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMinimalRevocationCertificateForFreshKeyTest() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice <alice@example.org>")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice <alice@example.org>");
|
||||
|
||||
PGPPublicKeyRing minimalRevocationCert = PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate(
|
||||
OpenPGPCertificate minimalRevocationCert = api.modify(secretKeys).createMinimalRevocationCertificate(
|
||||
SecretKeyRingProtector.unprotectedKeys(),
|
||||
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription());
|
||||
|
||||
assertEquals(1, minimalRevocationCert.size());
|
||||
PGPPublicKey key = minimalRevocationCert.getPublicKey();
|
||||
assertEquals(secretKeys.getPublicKey().getKeyID(), key.getKeyID());
|
||||
assertEquals(1, minimalRevocationCert.getKeys().size());
|
||||
PGPPublicKey key = minimalRevocationCert.getPGPPublicKeyRing().getPublicKey();
|
||||
assertEquals(secretKeys.getKeyIdentifier(), key.getKeyIdentifier());
|
||||
assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size());
|
||||
assertFalse(key.getUserIDs().hasNext());
|
||||
assertFalse(key.getUserAttributes().hasNext());
|
||||
assertNull(key.getTrustData());
|
||||
|
||||
PGPPublicKeyRing originalCert = PGPainless.extractCertificate(secretKeys);
|
||||
PGPPublicKeyRing mergedCert = PGPainless.mergeCertificate(originalCert, minimalRevocationCert);
|
||||
OpenPGPCertificate originalCert = secretKeys.toCertificate();
|
||||
OpenPGPCertificate mergedCert = api.mergeCertificate(originalCert, minimalRevocationCert);
|
||||
|
||||
assertTrue(PGPainless.inspectKeyRing(mergedCert).getRevocationState().isSoftRevocation());
|
||||
assertTrue(api.inspect(mergedCert).getRevocationState().isSoftRevocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMinimalRevocationCertificate_wrongReason() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate(
|
||||
() -> api.modify(secretKeys).createMinimalRevocationCertificate(
|
||||
SecretKeyRingProtector.unprotectedKeys(),
|
||||
RevocationAttributes.createCertificateRevocation()
|
||||
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
|
||||
|
|
|
@ -7,13 +7,14 @@ package org.pgpainless.key.modification;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -24,7 +25,7 @@ import org.pgpainless.util.TestAllImplementations;
|
|||
/**
|
||||
* Test that makes sure that PGPainless can deal with keys that carry a key
|
||||
* signature of type 0x10 (generic certification).
|
||||
*
|
||||
* <p>
|
||||
* Originally PGPainless would only handle keys with key signature type
|
||||
* 0x13 (positive certification) and would otherwise crash when negotiating
|
||||
* algorithms, esp. when revoking a key.
|
||||
|
@ -70,23 +71,26 @@ public class RevokeKeyWithGenericCertificationSignatureTest {
|
|||
}
|
||||
|
||||
private KeyPair revokeKey(String priv) throws IOException, PGPException {
|
||||
byte[] armoredBytes = priv.getBytes(StandardCharsets.UTF_8);
|
||||
PGPSecretKeyRing r = PGPainless.readKeyRing()
|
||||
.secretKeyRing(armoredBytes);
|
||||
PGPSecretKey secretKey = r.getSecretKey();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey key = api.readKey().parseKey(priv);
|
||||
OpenPGPKey onlyPrimaryKey = api.toKey(
|
||||
new PGPSecretKeyRing(
|
||||
Collections.singletonList(key.getPrimarySecretKey().getPGPSecretKey())
|
||||
)
|
||||
);
|
||||
// this is not ideal, but still valid usage
|
||||
PGPSecretKeyRing secretKeyRing =
|
||||
PGPainless.modifyKeyRing(new PGPSecretKeyRing(Arrays.asList(secretKey)))
|
||||
OpenPGPKey revokedPrimaryKey =
|
||||
api.modify(onlyPrimaryKey)
|
||||
.revoke(new UnprotectedKeysProtector()).done();
|
||||
|
||||
PGPPublicKey pkr = secretKeyRing.getPublicKeys().next();
|
||||
PGPPublicKey pkr = revokedPrimaryKey.getPGPSecretKeyRing().getPublicKeys().next();
|
||||
ByteArrayOutputStream pubOutBytes = new ByteArrayOutputStream();
|
||||
try (ArmoredOutputStream pubOut = ArmoredOutputStreamFactory.get(pubOutBytes)) {
|
||||
pkr.encode(pubOut);
|
||||
}
|
||||
pubOutBytes.close();
|
||||
|
||||
PGPSecretKey skr = secretKeyRing.getSecretKeys().next();
|
||||
PGPSecretKey skr = revokedPrimaryKey.getPGPSecretKeyRing().getSecretKeys().next();
|
||||
ByteArrayOutputStream secOutBytes = new ByteArrayOutputStream();
|
||||
try (ArmoredOutputStream privOut = ArmoredOutputStreamFactory.get(secOutBytes)) {
|
||||
skr.encode(privOut);
|
||||
|
|
|
@ -7,7 +7,7 @@ package org.pgpainless.key.modification;
|
|||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.JUtils;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -99,16 +99,17 @@ public class RevokeKeyWithoutPreferredAlgorithmsOnPrimaryKey {
|
|||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testChangingExpirationTimeWithKeyWithoutPrefAlgos()
|
||||
throws IOException {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
Date expirationDate = DateUtil.now();
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
|
||||
OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
|
||||
|
||||
SecretKeyRingProtector protector = new UnprotectedKeysProtector();
|
||||
|
||||
SecretKeyRingEditorInterface modify = PGPainless.modifyKeyRing(secretKeys)
|
||||
SecretKeyRingEditorInterface modify = api.modify(secretKeys)
|
||||
.setExpirationDate(expirationDate, protector);
|
||||
secretKeys = modify.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
|
||||
JUtils.assertDateEquals(expirationDate, info.getPrimaryKeyExpirationDate());
|
||||
}
|
||||
|
|
|
@ -19,8 +19,9 @@ import org.bouncycastle.bcpg.sig.IssuerFingerprint;
|
|||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPSignature;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestTemplate;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -33,7 +34,6 @@ import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditorInterfac
|
|||
import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
import org.pgpainless.signature.SignatureUtils;
|
||||
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
|
||||
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||
import org.pgpainless.util.TestAllImplementations;
|
||||
|
@ -43,10 +43,11 @@ public class RevokeSubKeyTest {
|
|||
|
||||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void revokeSukeyTest() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
public void revokeSubkeyTest() throws IOException, PGPException {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
|
||||
Iterator<PGPSecretKey> keysIterator = secretKeys.iterator();
|
||||
Iterator<PGPSecretKey> keysIterator = secretKeys.getPGPSecretKeyRing().iterator();
|
||||
PGPSecretKey primaryKey = keysIterator.next();
|
||||
PGPSecretKey subKey = keysIterator.next();
|
||||
|
||||
|
@ -55,10 +56,10 @@ public class RevokeSubKeyTest {
|
|||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys, Passphrase.fromPassword("password123"));
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeSubKey(new OpenPgpV4Fingerprint(subKey), protector)
|
||||
.done();
|
||||
keysIterator = secretKeys.iterator();
|
||||
keysIterator = secretKeys.getPGPSecretKeyRing().iterator();
|
||||
primaryKey = keysIterator.next();
|
||||
subKey = keysIterator.next();
|
||||
|
||||
|
@ -68,19 +69,20 @@ public class RevokeSubKeyTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void detachedRevokeSubkeyTest() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(secretKeys);
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("password123"));
|
||||
|
||||
PGPSignature revocationCertificate = PGPainless.modifyKeyRing(secretKeys)
|
||||
OpenPGPSignature revocationCertificate = api.modify(secretKeys)
|
||||
.createRevocation(fingerprint, protector, RevocationAttributes.createKeyRevocation()
|
||||
.withReason(RevocationAttributes.Reason.KEY_RETIRED)
|
||||
.withDescription("Key no longer used."));
|
||||
|
||||
PGPPublicKey publicKey = secretKeys.getPublicKey();
|
||||
PGPPublicKey publicKey = secretKeys.getPGPSecretKeyRing().getPublicKey();
|
||||
assertFalse(publicKey.hasRevocation());
|
||||
|
||||
publicKey = PGPPublicKey.addCertification(publicKey, revocationCertificate);
|
||||
publicKey = PGPPublicKey.addCertification(publicKey, revocationCertificate.getSignature());
|
||||
|
||||
assertTrue(publicKey.hasRevocation());
|
||||
}
|
||||
|
@ -88,19 +90,20 @@ public class RevokeSubKeyTest {
|
|||
@TestTemplate
|
||||
@ExtendWith(TestAllImplementations.class)
|
||||
public void testRevocationSignatureTypeCorrect() throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();
|
||||
Iterator<PGPPublicKey> keysIterator = secretKeys.getPublicKeys();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
|
||||
Iterator<PGPPublicKey> keysIterator = secretKeys.getPGPKeyRing().getPublicKeys();
|
||||
PGPPublicKey primaryKey = keysIterator.next();
|
||||
PGPPublicKey subKey = keysIterator.next();
|
||||
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
|
||||
.forKey(secretKeys, Passphrase.fromPassword("password123"));
|
||||
|
||||
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys);
|
||||
PGPSignature keyRevocation = editor.createRevocation(primaryKey.getKeyID(), protector, (RevocationAttributes) null);
|
||||
PGPSignature subkeyRevocation = editor.createRevocation(subKey.getKeyID(), protector, (RevocationAttributes) null);
|
||||
SecretKeyRingEditorInterface editor = api.modify(secretKeys);
|
||||
OpenPGPSignature keyRevocation = editor.createRevocation(primaryKey.getKeyIdentifier(), protector, (RevocationAttributes) null);
|
||||
OpenPGPSignature subkeyRevocation = editor.createRevocation(subKey.getKeyIdentifier(), protector, (RevocationAttributes) null);
|
||||
|
||||
assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignatureType());
|
||||
assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignatureType());
|
||||
assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignature().getSignatureType());
|
||||
assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignature().getSignatureType());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -126,39 +129,39 @@ public class RevokeSubKeyTest {
|
|||
@Test
|
||||
public void inspectSubpacketsOnDefaultRevocationSignature()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
PGPPublicKey encryptionSubkey = PGPainless.inspectKeyRing(secretKeys)
|
||||
PGPPublicKey encryptionSubkey = api.inspect(secretKeys)
|
||||
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
.revokeSubKey(encryptionSubkey.getKeyID(), protector)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeSubKey(encryptionSubkey.getKeyIdentifier(), protector)
|
||||
.done();
|
||||
|
||||
encryptionSubkey = secretKeys.getPublicKey(encryptionSubkey.getKeyID());
|
||||
encryptionSubkey = secretKeys.getPGPSecretKeyRing().getPublicKey(encryptionSubkey.getKeyIdentifier());
|
||||
PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next();
|
||||
assertNotNull(revocation);
|
||||
|
||||
assertArrayEquals(
|
||||
secretKeys.getPublicKey().getFingerprint(),
|
||||
secretKeys.getPGPSecretKeyRing().getPublicKey().getFingerprint(),
|
||||
revocation.getHashedSubPackets().getIssuerFingerprint().getFingerprint());
|
||||
assertEquals(secretKeys.getPublicKey().getKeyID(),
|
||||
assertEquals(secretKeys.getPGPSecretKeyRing().getPublicKey().getKeyID(),
|
||||
revocation.getHashedSubPackets().getIssuerKeyID());
|
||||
assertNull(SignatureSubpacketsUtil.getRevocationReason(revocation));
|
||||
assertTrue(SignatureUtils.isHardRevocation(revocation));
|
||||
assertTrue(revocation.isHardRevocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inspectSubpacketsOnModifiedRevocationSignature() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
PGPPublicKey encryptionSubkey = PGPainless.inspectKeyRing(secretKeys)
|
||||
PGPPublicKey encryptionSubkey = api.inspect(secretKeys)
|
||||
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
.revokeSubKey(encryptionSubkey.getKeyID(), protector, new RevocationSignatureSubpackets.Callback() {
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.revokeSubKey(encryptionSubkey.getKeyIdentifier(), protector, new RevocationSignatureSubpackets.Callback() {
|
||||
@Override
|
||||
public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) {
|
||||
hashedSubpackets.setRevocationReason(
|
||||
|
@ -171,14 +174,14 @@ public class RevokeSubKeyTest {
|
|||
})
|
||||
.done();
|
||||
|
||||
encryptionSubkey = secretKeys.getPublicKey(encryptionSubkey.getKeyID());
|
||||
encryptionSubkey = secretKeys.getPGPSecretKeyRing().getPublicKey(encryptionSubkey.getKeyIdentifier());
|
||||
PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next();
|
||||
assertNotNull(revocation);
|
||||
|
||||
assertNull(revocation.getHashedSubPackets().getIssuerFingerprint());
|
||||
assertEquals(secretKeys.getPublicKey().getKeyID(),
|
||||
assertEquals(secretKeys.getKeyIdentifier().getKeyId(),
|
||||
revocation.getHashedSubPackets().getIssuerKeyID());
|
||||
assertNotNull(SignatureSubpacketsUtil.getRevocationReason(revocation));
|
||||
assertFalse(SignatureUtils.isHardRevocation(revocation));
|
||||
assertFalse(revocation.isHardRevocation());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,46 +13,45 @@ import java.util.Date;
|
|||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.util.RevocationAttributes;
|
||||
import org.pgpainless.util.selection.userid.SelectUserId;
|
||||
|
||||
public class RevokeUserIdsTest {
|
||||
|
||||
@Test
|
||||
public void revokeWithSelectUserId() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("Allice <alice@example.org>", protector)
|
||||
.addUserId("Alice <alice@example.org>", protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
|
||||
assertTrue(info.isUserIdValid("Allice <alice@example.org>"));
|
||||
assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
|
||||
|
||||
Date n1 = new Date(info.getCreationDate().getTime() + 1000); // 1 sec later
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, n1)
|
||||
secretKeys = api.modify(secretKeys, n1)
|
||||
.revokeUserIds(
|
||||
SelectUserId.containsEmailAddress("alice@example.org"),
|
||||
protector,
|
||||
RevocationAttributes.createCertificateRevocation()
|
||||
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
|
||||
.withoutDescription())
|
||||
.withoutDescription(),
|
||||
uid -> uid.contains("alice@example.org"))
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, n1);
|
||||
info = api.inspect(secretKeys, n1);
|
||||
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
|
||||
assertFalse(info.isUserIdValid("Allice <alice@example.org>"));
|
||||
assertFalse(info.isUserIdValid("Alice <alice@example.org>"));
|
||||
|
@ -60,28 +59,28 @@ public class RevokeUserIdsTest {
|
|||
|
||||
@Test
|
||||
public void removeUserId() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>");
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("Allice <alice@example.org>", protector)
|
||||
.addUserId("Alice <alice@example.org>", protector)
|
||||
.done();
|
||||
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
KeyRingInfo info = api.inspect(secretKeys);
|
||||
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
|
||||
assertTrue(info.isUserIdValid("Allice <alice@example.org>"));
|
||||
assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
|
||||
|
||||
Date n1 = new Date(info.getCreationDate().getTime() + 1000);
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys, n1)
|
||||
secretKeys = api.modify(secretKeys, n1)
|
||||
.removeUserId("Allice <alice@example.org>", protector)
|
||||
.done();
|
||||
|
||||
info = PGPainless.inspectKeyRing(secretKeys, n1);
|
||||
info = api.inspect(secretKeys, n1);
|
||||
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
|
||||
assertFalse(info.isUserIdValid("Allice <alice@example.org>"));
|
||||
assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
|
||||
|
@ -95,14 +94,14 @@ public class RevokeUserIdsTest {
|
|||
|
||||
@Test
|
||||
public void emptySelectionYieldsNoSuchElementException() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Alice <alice@pgpainless.org>");
|
||||
|
||||
assertThrows(NoSuchElementException.class, () ->
|
||||
PGPainless.modifyKeyRing(secretKeys).revokeUserIds(
|
||||
SelectUserId.containsEmailAddress("alice@example.org"),
|
||||
api.modify(secretKeys).revokeUserIds(
|
||||
SecretKeyRingProtector.unprotectedKeys(),
|
||||
(RevocationAttributes) null));
|
||||
(RevocationAttributes) null,
|
||||
uid -> uid.contains("alice@example.org")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.bouncycastle.bcpg.SecretKeyPacket;
|
|||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -67,27 +68,27 @@ public class S2KUsageFixTest {
|
|||
@Test
|
||||
public void verifyOutFixInChangePassphraseWorks()
|
||||
throws PGPException {
|
||||
PGPSecretKeyRing before = PGPainless.generateKeyRing().modernKeyRing("Alice", "before")
|
||||
.getPGPSecretKeyRing();
|
||||
for (PGPSecretKey key : before) {
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey before = api.generateKey().modernKeyRing("Alice", "before");
|
||||
for (PGPSecretKey key : before.getPGPSecretKeyRing()) {
|
||||
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
|
||||
}
|
||||
|
||||
PGPSecretKeyRing unprotected = PGPainless.modifyKeyRing(before)
|
||||
OpenPGPKey unprotected = api.modify(before)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("before"))
|
||||
.withSecureDefaultSettings()
|
||||
.toNoPassphrase()
|
||||
.done();
|
||||
for (PGPSecretKey key : unprotected) {
|
||||
for (PGPSecretKey key : unprotected.getPGPSecretKeyRing()) {
|
||||
assertEquals(SecretKeyPacket.USAGE_NONE, key.getS2KUsage());
|
||||
}
|
||||
|
||||
PGPSecretKeyRing after = PGPainless.modifyKeyRing(unprotected)
|
||||
OpenPGPKey after = api.modify(unprotected)
|
||||
.changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase())
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword("after"))
|
||||
.done();
|
||||
for (PGPSecretKey key : after) {
|
||||
for (PGPSecretKey key : after.getPGPSecretKeyRing()) {
|
||||
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
|
||||
}
|
||||
}
|
||||
|
@ -95,18 +96,19 @@ public class S2KUsageFixTest {
|
|||
@Test
|
||||
public void testFixS2KUsageFrom_USAGE_CHECKSUM_to_USAGE_SHA1()
|
||||
throws IOException, PGPException {
|
||||
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(KEY_WITH_USAGE_CHECKSUM);
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey keys = api.readKey().parseKey(KEY_WITH_USAGE_CHECKSUM);
|
||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("after"));
|
||||
|
||||
PGPSecretKeyRing fixed = S2KUsageFix.replaceUsageChecksumWithUsageSha1(keys, protector);
|
||||
PGPSecretKeyRing fixed = S2KUsageFix.replaceUsageChecksumWithUsageSha1(keys.getPGPSecretKeyRing(), protector);
|
||||
for (PGPSecretKey key : fixed) {
|
||||
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
|
||||
}
|
||||
|
||||
testCanStillDecrypt(keys, protector);
|
||||
testCanStillDecrypt(api.toKey(fixed), protector);
|
||||
}
|
||||
|
||||
private void testCanStillDecrypt(PGPSecretKeyRing keys, SecretKeyRingProtector protector)
|
||||
private void testCanStillDecrypt(OpenPGPKey keys, SecretKeyRingProtector protector)
|
||||
throws PGPException, IOException {
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(MESSAGE.getBytes(StandardCharsets.UTF_8));
|
||||
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
|
|||
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPImplementation;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm;
|
||||
|
@ -43,7 +44,6 @@ import org.pgpainless.algorithm.SignatureType;
|
|||
import org.pgpainless.key.TestKeys;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
import org.pgpainless.key.protection.UnlockSecretKey;
|
||||
import org.pgpainless.policy.Policy;
|
||||
import org.pgpainless.signature.consumer.SignaturePicker;
|
||||
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||
|
||||
|
@ -51,17 +51,17 @@ public class SignatureSubpacketsUtilTest {
|
|||
|
||||
@Test
|
||||
public void testGetKeyExpirationTimeAsDate() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("Expire")
|
||||
.getPGPSecretKeyRing();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.modernKeyRing("Expire");
|
||||
Date expiration = Date.from(new Date().toInstant().plus(365, ChronoUnit.DAYS));
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.setExpirationDate(expiration, SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
PGPSignature expirationSig = SignaturePicker.pickCurrentUserIdCertificationSignature(
|
||||
secretKeys, "Expire", Policy.getInstance(), new Date());
|
||||
OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = PGPainless.inspectKeyRing(secretKeys).getSigningSubkeys().get(0);
|
||||
secretKeys.getPGPSecretKeyRing(), "Expire", api.getAlgorithmPolicy(), new Date());
|
||||
OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = api.inspect(secretKeys).getSigningSubkeys().get(0);
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () ->
|
||||
SignatureSubpacketsUtil.getKeyExpirationTimeAsDate(expirationSig, notTheRightKey.getPGPPublicKey()));
|
||||
|
@ -69,18 +69,19 @@ public class SignatureSubpacketsUtilTest {
|
|||
|
||||
@Test
|
||||
public void testGetRevocable() throws PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
|
||||
PGPPrivateKey certKey = UnlockSecretKey.unlockSecretKey(secretKeys.getSecretKey(), SecretKeyRingProtector.unprotectedKeys());
|
||||
OpenPGPKey secretKeys = TestKeys.getEmilKey();
|
||||
PGPPrivateKey certKey = UnlockSecretKey.unlockSecretKey(secretKeys.getPrimarySecretKey().getPGPSecretKey(),
|
||||
SecretKeyRingProtector.unprotectedKeys());
|
||||
|
||||
PGPSignatureGenerator generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION);
|
||||
PGPSignature withoutRevocable = generator.generateCertification(secretKeys.getPublicKey());
|
||||
PGPSignature withoutRevocable = generator.generateCertification(secretKeys.getPrimaryKey().getPGPPublicKey());
|
||||
assertNull(SignatureSubpacketsUtil.getRevocable(withoutRevocable));
|
||||
|
||||
generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION);
|
||||
PGPSignatureSubpacketGenerator hashed = new PGPSignatureSubpacketGenerator();
|
||||
hashed.setRevocable(true, true);
|
||||
generator.setHashedSubpackets(hashed.generate());
|
||||
PGPSignature withRevocable = generator.generateCertification(secretKeys.getPublicKey());
|
||||
PGPSignature withRevocable = generator.generateCertification(secretKeys.getPrimaryKey().getPGPPublicKey());
|
||||
assertNotNull(SignatureSubpacketsUtil.getRevocable(withRevocable));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||
|
@ -24,17 +24,17 @@ public class SelectUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testSelectUserIds() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing("<alice@wonderland.lit>")
|
||||
.getPGPSecretKeyRing();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey()
|
||||
.simpleEcKeyRing("<alice@wonderland.lit>");
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId(
|
||||
UserId.builder().withName("Alice Liddell").noComment()
|
||||
.withEmail("crazy@the-rabbit.hole").build(),
|
||||
SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds();
|
||||
List<String> userIds = api.inspect(secretKeys).getValidUserIds();
|
||||
List<String> validEmail = userIds.stream().filter(SelectUserId.and(
|
||||
SelectUserId.validUserId(secretKeys),
|
||||
SelectUserId.containsEmailAddress("alice@wonderland.lit")
|
||||
|
@ -54,14 +54,14 @@ public class SelectUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testContainsSubstring() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("wine drinker")
|
||||
.getPGPSecretKeyRing();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("wine drinker");
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("this is not a quine", SecretKeyRingProtector.unprotectedKeys())
|
||||
.addUserId("this is not a crime", SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds();
|
||||
List<String> userIds = api.inspect(secretKeys).getValidUserIds();
|
||||
|
||||
List<String> containSubstring = userIds.stream().filter(SelectUserId.containsSubstring("ine")).collect(Collectors.toList());
|
||||
assertEquals(Arrays.asList("wine drinker", "this is not a quine"), containSubstring);
|
||||
|
@ -69,9 +69,9 @@ public class SelectUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testContainsEmailAddress() {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("Alice <alice@wonderland.lit>")
|
||||
.getPGPSecretKeyRing();
|
||||
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds();
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("Alice <alice@wonderland.lit>");
|
||||
List<String> userIds = api.inspect(secretKeys).getValidUserIds();
|
||||
|
||||
assertEquals("Alice <alice@wonderland.lit>", userIds.stream().filter(
|
||||
SelectUserId.containsEmailAddress("alice@wonderland.lit")).findFirst().get());
|
||||
|
@ -83,15 +83,15 @@ public class SelectUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testAndOrNot() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("Alice <alice@wonderland.lit>")
|
||||
.getPGPSecretKeyRing();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("Alice <alice@wonderland.lit>");
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("Alice <another@email.address>", SecretKeyRingProtector.unprotectedKeys())
|
||||
.addUserId("<crazy@the-rabbit.hole>", SecretKeyRingProtector.unprotectedKeys())
|
||||
.addUserId("Crazy Girl <alice@wonderland.lit>", SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
|
||||
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds();
|
||||
List<String> userIds = api.inspect(secretKeys).getValidUserIds();
|
||||
|
||||
List<String> or = userIds.stream().filter(SelectUserId.or(
|
||||
SelectUserId.containsEmailAddress("alice@wonderland.lit"),
|
||||
|
@ -110,12 +110,12 @@ public class SelectUserIdTest {
|
|||
|
||||
@Test
|
||||
public void testFirstMatch() throws PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("First UserID")
|
||||
.getPGPSecretKeyRing();
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("First UserID");
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.addUserId("Second UserID", SecretKeyRingProtector.unprotectedKeys())
|
||||
.done();
|
||||
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds();
|
||||
List<String> userIds = api.inspect(secretKeys).getValidUserIds();
|
||||
assertEquals("First UserID", userIds.stream().filter(SelectUserId.validUserId(secretKeys)).findFirst().get());
|
||||
assertEquals("Second UserID", userIds.stream().filter(SelectUserId.containsSubstring("Second")).findFirst().get());
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@ import java.io.InputStream
|
|||
import java.io.OutputStream
|
||||
import java.lang.RuntimeException
|
||||
import org.bouncycastle.openpgp.PGPException
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||
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
|
||||
import org.pgpainless.key.util.RevocationAttributes
|
||||
|
@ -38,7 +39,7 @@ class RevokeKeyImpl : RevokeKey {
|
|||
|
||||
secretKeyRings.forEach { protector.addSecretKey(it) }
|
||||
|
||||
val revocationCertificates = mutableListOf<PGPPublicKeyRing>()
|
||||
val revocationCertificates = mutableListOf<OpenPGPCertificate>()
|
||||
secretKeyRings.forEach { secretKeys ->
|
||||
val editor = PGPainless.modifyKeyRing(secretKeys)
|
||||
try {
|
||||
|
@ -53,7 +54,8 @@ class RevokeKeyImpl : RevokeKey {
|
|||
val certificate = PGPainless.extractCertificate(secretKeys)
|
||||
val revocation = editor.createRevocation(protector, attributes)
|
||||
revocationCertificates.add(
|
||||
KeyRingUtils.injectCertification(certificate, revocation))
|
||||
KeyRingUtils.injectCertification(certificate, revocation.signature)
|
||||
.toOpenPGPCertificate())
|
||||
}
|
||||
} catch (e: WrongPassphraseException) {
|
||||
throw SOPGPException.KeyIsProtected(
|
||||
|
@ -67,7 +69,8 @@ class RevokeKeyImpl : RevokeKey {
|
|||
|
||||
return object : Ready() {
|
||||
override fun writeTo(outputStream: OutputStream) {
|
||||
val collection = PGPPublicKeyRingCollection(revocationCertificates)
|
||||
val collection =
|
||||
PGPPublicKeyRingCollection(revocationCertificates.map { it.pgpPublicKeyRing })
|
||||
if (armor) {
|
||||
val armorOut = ArmoredOutputStreamFactory.get(outputStream)
|
||||
collection.encode(armorOut)
|
||||
|
|
|
@ -7,7 +7,7 @@ package sop.testsuite.pgpainless.operation;
|
|||
import org.bouncycastle.bcpg.KeyIdentifier;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.api.OpenPGPKey;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.pgpainless.PGPainless;
|
||||
|
@ -32,13 +32,13 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest {
|
|||
@ParameterizedTest
|
||||
@MethodSource("provideInstances")
|
||||
public void changePasswordOfKeyWithSeparateSubkeyPasswords(SOP sop) throws IOException, PGPException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing()
|
||||
PGPainless api = PGPainless.getInstance();
|
||||
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
|
||||
.addSubkey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA))
|
||||
.addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE))
|
||||
.build()
|
||||
.getPGPSecretKeyRing();
|
||||
Iterator<PGPPublicKey> keys = secretKeys.getPublicKeys();
|
||||
.build();
|
||||
Iterator<PGPPublicKey> keys = secretKeys.getPGPSecretKeyRing().getPublicKeys();
|
||||
KeyIdentifier primaryKeyId = keys.next().getKeyIdentifier();
|
||||
KeyIdentifier signingKeyId = keys.next().getKeyIdentifier();
|
||||
KeyIdentifier encryptKeyId = keys.next().getKeyIdentifier();
|
||||
|
@ -47,7 +47,7 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest {
|
|||
String p2 = "0r4ng3";
|
||||
String p3 = "dr4g0n";
|
||||
|
||||
secretKeys = PGPainless.modifyKeyRing(secretKeys)
|
||||
secretKeys = api.modify(secretKeys)
|
||||
.changeSubKeyPassphraseFromOldPassphrase(primaryKeyId, Passphrase.emptyPassphrase())
|
||||
.withSecureDefaultSettings()
|
||||
.toNewPassphrase(Passphrase.fromPassword(p1))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue