• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pgpainless / pgpainless / #1051

25 Mar 2025 11:09AM UTC coverage: 86.854% (+0.03%) from 86.822%
#1051

push

github

vanitasvitae
PGPainless 1.7.6-SNAPSHOT

6567 of 7561 relevant lines covered (86.85%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.08
/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignatureValidator.kt
1
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
2
//
3
// SPDX-License-Identifier: Apache-2.0
4

5
package org.pgpainless.signature.consumer
6

7
import java.lang.Exception
8
import java.util.Date
9
import openpgp.formatUTC
10
import openpgp.openPgpKeyId
11
import org.bouncycastle.openpgp.PGPException
12
import org.bouncycastle.openpgp.PGPPublicKey
13
import org.bouncycastle.openpgp.PGPSignature
14
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector
15
import org.pgpainless.algorithm.KeyFlag
16
import org.pgpainless.algorithm.SignatureSubpacket
17
import org.pgpainless.algorithm.SignatureType
18
import org.pgpainless.bouncycastle.extensions.fingerprint
19
import org.pgpainless.bouncycastle.extensions.isHardRevocation
20
import org.pgpainless.bouncycastle.extensions.isOfType
21
import org.pgpainless.bouncycastle.extensions.publicKeyAlgorithm
22
import org.pgpainless.bouncycastle.extensions.signatureExpirationDate
23
import org.pgpainless.bouncycastle.extensions.signatureHashAlgorithm
24
import org.pgpainless.exception.SignatureValidationException
25
import org.pgpainless.implementation.ImplementationFactory
26
import org.pgpainless.key.OpenPgpFingerprint
27
import org.pgpainless.policy.Policy
28
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil
29
import org.pgpainless.util.NotationRegistry
30

31
abstract class SignatureValidator {
1✔
32

33
    @Throws(SignatureValidationException::class) abstract fun verify(signature: PGPSignature)
34

35
    companion object {
36

37
        /**
38
         * Check, whether there is the possibility that the given signature was created by the given
39
         * key. [verify] throws a [SignatureValidationException] if we can say with certainty that
40
         * the signature was not created by the given key (e.g. if the sig carries another issuer,
41
         * issuer fingerprint packet).
42
         *
43
         * If there is no information found in the signature about who created it (no issuer, no
44
         * fingerprint), [verify] will simply return since it is plausible that the given key
45
         * created the sig.
46
         *
47
         * @param signingKey signing key
48
         * @return validator that throws a [SignatureValidationException] if the signature was not
49
         *   possibly made by the given key.
50
         */
51
        @JvmStatic
52
        fun wasPossiblyMadeByKey(signingKey: PGPPublicKey): SignatureValidator {
53
            return object : SignatureValidator() {
1✔
54
                override fun verify(signature: PGPSignature) {
55
                    val signingKeyFingerprint = OpenPgpFingerprint.of(signingKey)
1✔
56
                    val issuer = SignatureSubpacketsUtil.getIssuerKeyIdAsLong(signature)
1✔
57

58
                    if (issuer != null) {
1✔
59
                        if (issuer != signingKey.keyID) {
1✔
60
                            throw SignatureValidationException(
1✔
61
                                "Signature was not created by" +
62
                                    " $signingKeyFingerprint (signature issuer: ${issuer.openPgpKeyId()})")
1✔
63
                        }
64
                    }
65

66
                    if (signature.fingerprint != null &&
1✔
67
                        signature.fingerprint != signingKeyFingerprint) {
1✔
68
                        throw SignatureValidationException(
1✔
69
                            "Signature was not created by" +
70
                                " $signingKeyFingerprint (signature fingerprint: ${signature.fingerprint})")
1✔
71
                    }
72
                }
1✔
73

74
                // No issuer information found, so we cannot rule out that we did not create the sig
75
            }
76
        }
77

78
        /**
79
         * Verify that a subkey binding signature - if the subkey is signing-capable - contains a
80
         * valid primary key binding signature.
81
         *
82
         * @param primaryKey primary key
83
         * @param subkey subkey
84
         * @param policy policy
85
         * @param referenceDate reference date for signature verification
86
         * @return validator
87
         */
88
        @JvmStatic
89
        fun hasValidPrimaryKeyBindingSignatureIfRequired(
90
            primaryKey: PGPPublicKey,
91
            subkey: PGPPublicKey,
92
            policy: Policy,
93
            referenceTime: Date
94
        ): SignatureValidator {
95
            return object : SignatureValidator() {
1✔
96
                override fun verify(signature: PGPSignature) {
97
                    if (!signature.publicKeyAlgorithm.isSigningCapable()) {
1✔
98
                        // subkey is not signing capable -> No need to process embedded signatures
99
                        return
×
100
                    }
101

102
                    // Make sure we have key flags
103
                    SignatureSubpacketsUtil.getKeyFlags(signature)?.let {
1✔
104
                        if (!KeyFlag.hasKeyFlag(it.flags, KeyFlag.SIGN_DATA) &&
1✔
105
                            !KeyFlag.hasKeyFlag(it.flags, KeyFlag.CERTIFY_OTHER)) {
×
106
                            return
×
107
                        }
108
                    }
1✔
109
                        ?: return
×
110

111
                    try {
1✔
112
                        val embeddedSignatures =
1✔
113
                            SignatureSubpacketsUtil.getEmbeddedSignature(signature)
1✔
114
                        if (embeddedSignatures.isEmpty) {
1✔
115
                            throw SignatureValidationException(
×
116
                                "Missing primary key binding" +
117
                                    " signature on signing capable subkey ${subkey.keyID.openPgpKeyId()}",
×
118
                                mapOf())
×
119
                        }
120

121
                        val rejectedEmbeddedSignatures = mutableMapOf<PGPSignature, Exception>()
1✔
122
                        if (!embeddedSignatures.any { embedded ->
1✔
123
                            if (embedded.isOfType(SignatureType.PRIMARYKEY_BINDING)) {
1✔
124
                                try {
1✔
125
                                    signatureStructureIsAcceptable(subkey, policy).verify(embedded)
1✔
126
                                    signatureIsEffective(referenceTime).verify(embedded)
1✔
127
                                    correctPrimaryKeyBindingSignature(primaryKey, subkey)
1✔
128
                                        .verify(embedded)
1✔
129
                                    return@any true
1✔
130
                                } catch (e: SignatureValidationException) {
1✔
131
                                    rejectedEmbeddedSignatures[embedded] = e
1✔
132
                                }
133
                            }
134
                            false
1✔
135
                        }) {
136
                            throw SignatureValidationException(
1✔
137
                                "Missing primary key binding signature on signing capable subkey ${subkey.keyID.openPgpKeyId()}",
1✔
138
                                rejectedEmbeddedSignatures)
1✔
139
                        }
140
                    } catch (e: PGPException) {
1✔
141
                        throw SignatureValidationException(
1✔
142
                            "Cannot process list of embedded signatures.", e)
1✔
143
                    }
144
                }
1✔
145
            }
146
        }
147

148
        /**
149
         * Verify that a signature has an acceptable structure.
150
         *
151
         * @param signingKey signing key
152
         * @param policy policy
153
         * @return validator
154
         */
155
        @JvmStatic
156
        fun signatureStructureIsAcceptable(
157
            signingKey: PGPPublicKey,
158
            policy: Policy
159
        ): SignatureValidator {
160
            return object : SignatureValidator() {
1✔
161
                override fun verify(signature: PGPSignature) {
162
                    signatureIsNotMalformed(signingKey).verify(signature)
1✔
163
                    if (signature.version >= 4) {
1✔
164
                        signatureDoesNotHaveCriticalUnknownNotations(policy.notationRegistry)
1✔
165
                            .verify(signature)
1✔
166
                        signatureDoesNotHaveCriticalUnknownSubpackets().verify(signature)
1✔
167
                    }
168
                    signatureUsesAcceptableHashAlgorithm(policy).verify(signature)
1✔
169
                    signatureUsesAcceptablePublicKeyAlgorithm(policy, signingKey).verify(signature)
1✔
170
                }
1✔
171
            }
172
        }
173

174
        /**
175
         * Verify that a signature was made using an acceptable [PublicKeyAlgorithm].
176
         *
177
         * @param policy policy
178
         * @param signingKey signing key
179
         * @return validator
180
         */
181
        @JvmStatic
182
        fun signatureUsesAcceptablePublicKeyAlgorithm(
183
            policy: Policy,
184
            signingKey: PGPPublicKey
185
        ): SignatureValidator {
186
            return object : SignatureValidator() {
1✔
187
                override fun verify(signature: PGPSignature) {
188
                    if (signingKey.bitStrength == -1) {
1✔
189
                        throw SignatureValidationException(
×
190
                            "Cannot determine bit strength of signing key.")
×
191
                    }
192
                    if (!policy.publicKeyAlgorithmPolicy.isAcceptable(
1✔
193
                        signingKey.publicKeyAlgorithm, signingKey.bitStrength)) {
1✔
194
                        throw SignatureValidationException(
×
195
                            "Signature was made using unacceptable key. " +
196
                                "${signingKey.publicKeyAlgorithm} (${signingKey.bitStrength} bits) is " +
×
197
                                "not acceptable according to the public key algorithm policy.")
198
                    }
199
                }
1✔
200
            }
201
        }
202

203
        @JvmStatic
204
        fun signatureUsesAcceptableHashAlgorithm(policy: Policy): SignatureValidator {
205
            return object : SignatureValidator() {
1✔
206
                override fun verify(signature: PGPSignature) {
207
                    try {
1✔
208
                        val algorithmPolicy = getHashAlgorithmPolicyForSignature(signature, policy)
1✔
209
                        if (!algorithmPolicy.isAcceptable(
1✔
210
                            signature.signatureHashAlgorithm, signature.creationTime)) {
1✔
211
                            throw SignatureValidationException(
×
212
                                "Signature uses unacceptable" +
213
                                    " hash algorithm ${signature.signatureHashAlgorithm}" +
×
214
                                    " (Signature creation time: ${signature.creationTime.formatUTC()})")
×
215
                        }
216
                    } catch (e: NoSuchElementException) {
×
217
                        throw SignatureValidationException(
×
218
                            "Signature uses unknown hash" + " algorithm ${signature.hashAlgorithm}")
×
219
                    }
220
                }
1✔
221
            }
222
        }
223

224
        /**
225
         * Return the applicable [Policy.HashAlgorithmPolicy] for the given [PGPSignature].
226
         * Revocation signatures are being policed using a different policy than non-revocation
227
         * signatures.
228
         *
229
         * @param signature signature
230
         * @param policy revocation policy for revocation sigs, normal policy for non-rev sigs
231
         * @return policy
232
         */
233
        @JvmStatic
234
        private fun getHashAlgorithmPolicyForSignature(
235
            signature: PGPSignature,
236
            policy: Policy
237
        ): Policy.HashAlgorithmPolicy {
238
            return when (SignatureType.fromCode(signature.signatureType)) {
1✔
239
                null -> policy.certificationSignatureHashAlgorithmPolicy
×
240
                SignatureType.CERTIFICATION_REVOCATION,
241
                SignatureType.KEY_REVOCATION,
242
                SignatureType.SUBKEY_REVOCATION -> policy.revocationSignatureHashAlgorithmPolicy
1✔
243
                SignatureType.GENERIC_CERTIFICATION,
244
                SignatureType.NO_CERTIFICATION,
245
                SignatureType.CASUAL_CERTIFICATION,
246
                SignatureType.POSITIVE_CERTIFICATION,
247
                SignatureType.DIRECT_KEY,
248
                SignatureType.SUBKEY_BINDING,
249
                SignatureType.PRIMARYKEY_BINDING -> policy.certificationSignatureHashAlgorithmPolicy
1✔
250
                else -> policy.dataSignatureHashAlgorithmPolicy
1✔
251
            }
252
        }
253

254
        /**
255
         * Verify that a signature does not carry critical unknown notations.
256
         *
257
         * @param registry notation registry of known notations
258
         * @return validator
259
         */
260
        @JvmStatic
261
        fun signatureDoesNotHaveCriticalUnknownNotations(
262
            registry: NotationRegistry
263
        ): SignatureValidator {
264
            return object : SignatureValidator() {
1✔
265
                override fun verify(signature: PGPSignature) {
266
                    SignatureSubpacketsUtil.getHashedNotationData(signature)
1✔
267
                        .filter { it.isCritical && !registry.isKnownNotation(it.notationName) }
1✔
268
                        .forEach {
1✔
269
                            throw SignatureValidationException(
1✔
270
                                "Signature contains unknown critical notation '${it.notationName}' in its hashed area.")
1✔
271
                        }
272
                }
1✔
273
            }
274
        }
275

276
        /**
277
         * Verify that a signature does not contain critical unknown subpackets.
278
         *
279
         * @return validator
280
         */
281
        @JvmStatic
282
        fun signatureDoesNotHaveCriticalUnknownSubpackets(): SignatureValidator {
283
            return object : SignatureValidator() {
1✔
284
                override fun verify(signature: PGPSignature) {
285
                    signature.hashedSubPackets.criticalTags.forEach {
1✔
286
                        try {
1✔
287
                            SignatureSubpacket.requireFromCode(it)
1✔
288
                        } catch (e: NoSuchElementException) {
1✔
289
                            throw SignatureValidationException(
1✔
290
                                "Signature contains unknown critical subpacket of type 0x${Integer.toHexString(it)}")
1✔
291
                        }
292
                    }
1✔
293
                }
1✔
294
            }
295
        }
296

297
        /**
298
         * Verify that a signature is effective at the given reference date.
299
         *
300
         * @param referenceTime reference date for signature verification
301
         * @return validator
302
         */
303
        @JvmStatic
304
        @JvmOverloads
305
        fun signatureIsEffective(referenceTime: Date = Date()): SignatureValidator {
1✔
306
            return object : SignatureValidator() {
1✔
307
                override fun verify(signature: PGPSignature) {
308
                    signatureIsAlreadyEffective(referenceTime).verify(signature)
1✔
309
                    signatureIsNotYetExpired(referenceTime).verify(signature)
1✔
310
                }
1✔
311
            }
312
        }
313

314
        /**
315
         * Verify that a signature was created prior to the given reference date.
316
         *
317
         * @param referenceTime reference date for signature verification
318
         * @return validator
319
         */
320
        @JvmStatic
321
        fun signatureIsAlreadyEffective(referenceTime: Date): SignatureValidator {
322
            return object : SignatureValidator() {
1✔
323
                override fun verify(signature: PGPSignature) {
324
                    if (signature.isHardRevocation) {
1✔
325
                        return
1✔
326
                    }
327
                    if (signature.creationTime > referenceTime) {
1✔
328
                        throw SignatureValidationException(
1✔
329
                            "Signature was created at ${signature.creationTime.formatUTC()} and" +
1✔
330
                                " is therefore not yet valid at ${referenceTime.formatUTC()}")
1✔
331
                    }
332
                }
1✔
333
            }
334
        }
335

336
        /**
337
         * Verify that a signature is not yet expired.
338
         *
339
         * @param referenceTime reference date for signature verification
340
         * @return validator
341
         */
342
        @JvmStatic
343
        fun signatureIsNotYetExpired(referenceTime: Date): SignatureValidator {
344
            return object : SignatureValidator() {
1✔
345
                override fun verify(signature: PGPSignature) {
346
                    if (signature.isHardRevocation) {
1✔
347
                        return
1✔
348
                    }
349
                    val expirationDate = signature.signatureExpirationDate
1✔
350
                    if (expirationDate != null && expirationDate < referenceTime) {
1✔
351
                        throw SignatureValidationException(
1✔
352
                            "Signature is already expired " +
353
                                "(expiration: ${expirationDate.formatUTC()}," +
1✔
354
                                " validation: ${referenceTime.formatUTC()})")
1✔
355
                    }
356
                }
1✔
357
            }
358
        }
359

360
        /**
361
         * Verify that a signature is not malformed. A signature is malformed if it has no hashed
362
         * creation time subpacket, it predates the creation time of the signing key, or it predates
363
         * the creation date of the signing key binding signature.
364
         *
365
         * @param signingKey signing key
366
         * @return validator
367
         */
368
        @JvmStatic
369
        fun signatureIsNotMalformed(signingKey: PGPPublicKey): SignatureValidator {
370
            return object : SignatureValidator() {
1✔
371
                override fun verify(signature: PGPSignature) {
372
                    if (signature.version >= 4) {
1✔
373
                        signatureHasHashedCreationTime().verify(signature)
1✔
374
                    }
375
                    signatureDoesNotPredateSigningKey(signingKey).verify(signature)
1✔
376
                    if (!signature.isOfType(SignatureType.PRIMARYKEY_BINDING)) {
1✔
377
                        signatureDoesNotPredateSigningKeyBindingDate(signingKey).verify(signature)
1✔
378
                    }
379
                }
1✔
380
            }
381
        }
382

383
        @JvmStatic
384
        fun signatureDoesNotPredateSignee(signee: PGPPublicKey): SignatureValidator {
385
            return signatureDoesNotPredateKeyCreation(signee)
1✔
386
        }
387

388
        /**
389
         * Verify that a signature does not predate the creation time of the signing key.
390
         *
391
         * @param key signing key
392
         * @return validator
393
         */
394
        @JvmStatic
395
        fun signatureDoesNotPredateSigningKey(signingKey: PGPPublicKey): SignatureValidator {
396
            return signatureDoesNotPredateKeyCreation(signingKey)
1✔
397
        }
398

399
        /**
400
         * Verify that a signature does not predate the creation time of the given key.
401
         *
402
         * @param key key
403
         * @return validator
404
         */
405
        @JvmStatic
406
        fun signatureDoesNotPredateKeyCreation(key: PGPPublicKey): SignatureValidator {
407
            return object : SignatureValidator() {
1✔
408
                override fun verify(signature: PGPSignature) {
409
                    if (key.creationTime > signature.creationTime) {
1✔
410
                        throw SignatureValidationException(
1✔
411
                            "Signature predates key" +
412
                                " (key creation: ${key.creationTime.formatUTC()}," +
1✔
413
                                " signature creation: ${signature.creationTime.formatUTC()})")
1✔
414
                    }
415
                }
1✔
416
            }
417
        }
418

419
        /**
420
         * Verify that a signature has a hashed creation time subpacket.
421
         *
422
         * @return validator
423
         */
424
        @JvmStatic
425
        fun signatureHasHashedCreationTime(): SignatureValidator {
426
            return object : SignatureValidator() {
1✔
427
                override fun verify(signature: PGPSignature) {
428
                    if (SignatureSubpacketsUtil.getSignatureCreationTime(signature) == null) {
1✔
429
                        throw SignatureValidationException(
×
430
                            "Malformed signature." +
×
431
                                "Signature has no signature creation time subpacket in its hashed area.")
432
                    }
433
                }
1✔
434
            }
435
        }
436

437
        /**
438
         * Verify that a signature does not predate the binding date of the signing key.
439
         *
440
         * @param signingKey signing key
441
         * @return validator
442
         */
443
        @JvmStatic
444
        fun signatureDoesNotPredateSigningKeyBindingDate(
445
            signingKey: PGPPublicKey
446
        ): SignatureValidator {
447
            return object : SignatureValidator() {
1✔
448
                override fun verify(signature: PGPSignature) {
449
                    if (signingKey.isMasterKey) {
1✔
450
                        return
1✔
451
                    }
452
                    if (signingKey
1✔
453
                        .getSignaturesOfType(SignatureType.SUBKEY_BINDING.code)
1✔
454
                        .asSequence()
1✔
455
                        .map {
1✔
456
                            if (signature.creationTime < it.creationTime) {
×
457
                                throw SignatureValidationException(
×
458
                                    "Signature was created " +
×
459
                                        "before the signing key was bound to the certificate.")
460
                            }
461
                        }
×
462
                        .none()) {
1✔
463
                        throw SignatureValidationException(
×
464
                            "Signing subkey does not have a subkey binding signature.")
×
465
                    }
466
                }
1✔
467
            }
468
        }
469

470
        /**
471
         * Verify that a subkey binding signature is correct.
472
         *
473
         * @param primaryKey primary key
474
         * @param subkey subkey
475
         * @return validator
476
         */
477
        @JvmStatic
478
        fun correctSubkeyBindingSignature(
479
            primaryKey: PGPPublicKey,
480
            subkey: PGPPublicKey
481
        ): SignatureValidator {
482
            return object : SignatureValidator() {
1✔
483
                override fun verify(signature: PGPSignature) {
484
                    if (primaryKey.keyID == subkey.keyID) {
1✔
485
                        throw SignatureValidationException("Primary key cannot be its own subkey.")
×
486
                    }
487
                    try {
1✔
488
                        signature.init(
1✔
489
                            ImplementationFactory.getInstance().pgpContentVerifierBuilderProvider,
1✔
490
                            primaryKey)
1✔
491
                        if (!signature.verifyCertification(primaryKey, subkey)) {
1✔
492
                            throw SignatureValidationException("Signature is not correct.")
×
493
                        }
494
                    } catch (e: PGPException) {
×
495
                        throw SignatureValidationException(
×
496
                            "Cannot verify subkey binding signature correctness", e)
×
497
                    } catch (e: ClassCastException) {
×
498
                        throw SignatureValidationException(
×
499
                            "Cannot verify subkey binding signature correctness", e)
×
500
                    }
501
                }
1✔
502
            }
503
        }
504

505
        /**
506
         * Verify that a primary key binding signature is correct.
507
         *
508
         * @param primaryKey primary key
509
         * @param subkey subkey
510
         * @return validator
511
         */
512
        @JvmStatic
513
        fun correctPrimaryKeyBindingSignature(
514
            primaryKey: PGPPublicKey,
515
            subkey: PGPPublicKey
516
        ): SignatureValidator {
517
            return object : SignatureValidator() {
1✔
518
                override fun verify(signature: PGPSignature) {
519
                    if (primaryKey.keyID == subkey.keyID) {
1✔
520
                        throw SignatureValidationException("Primary key cannot be its own subkey.")
×
521
                    }
522
                    try {
1✔
523
                        signature.init(
1✔
524
                            ImplementationFactory.getInstance().pgpContentVerifierBuilderProvider,
1✔
525
                            subkey)
1✔
526
                        if (!signature.verifyCertification(primaryKey, subkey)) {
1✔
527
                            throw SignatureValidationException(
1✔
528
                                "Primary Key Binding Signature is not correct.")
1✔
529
                        }
530
                    } catch (e: PGPException) {
1✔
531
                        throw SignatureValidationException(
1✔
532
                            "Cannot verify primary key binding signature correctness", e)
1✔
533
                    } catch (e: ClassCastException) {
×
534
                        throw SignatureValidationException(
×
535
                            "Cannot verify primary key binding signature correctness", e)
×
536
                    }
537
                }
1✔
538
            }
539
        }
540

541
        /**
542
         * Verify that a direct-key signature is correct.
543
         *
544
         * @param signingKey signing key
545
         * @param signedKey signed key
546
         * @return validator
547
         */
548
        @JvmStatic
549
        fun correctSignatureOverKey(
550
            signingKey: PGPPublicKey,
551
            signedKey: PGPPublicKey
552
        ): SignatureValidator {
553
            return object : SignatureValidator() {
1✔
554
                override fun verify(signature: PGPSignature) {
555
                    try {
1✔
556
                        signature.init(
1✔
557
                            ImplementationFactory.getInstance().pgpContentVerifierBuilderProvider,
1✔
558
                            signingKey)
1✔
559
                        val valid =
1✔
560
                            if (signingKey.keyID == signedKey.keyID ||
1✔
561
                                signature.isOfType(SignatureType.DIRECT_KEY)) {
1✔
562
                                signature.verifyCertification(signedKey)
1✔
563
                            } else {
564
                                signature.verifyCertification(signingKey, signedKey)
1✔
565
                            }
566
                        if (!valid) {
1✔
567
                            throw SignatureValidationException("Signature is not correct.")
×
568
                        }
569
                    } catch (e: PGPException) {
×
570
                        throw SignatureValidationException(
×
571
                            "Cannot verify direct-key signature correctness", e)
×
572
                    } catch (e: ClassCastException) {
×
573
                        throw SignatureValidationException(
×
574
                            "Cannot verify direct-key signature correctness", e)
×
575
                    }
576
                }
1✔
577
            }
578
        }
579

580
        @JvmStatic
581
        fun signatureIsCertification(): SignatureValidator {
582
            return signatureIsOfType(
1✔
583
                SignatureType.POSITIVE_CERTIFICATION,
1✔
584
                SignatureType.CASUAL_CERTIFICATION,
1✔
585
                SignatureType.GENERIC_CERTIFICATION,
1✔
586
                SignatureType.NO_CERTIFICATION)
1✔
587
        }
588

589
        /**
590
         * Verify that a signature type equals one of the given [SignatureType].
591
         *
592
         * @param signatureType one or more signature types
593
         * @return validator
594
         */
595
        @JvmStatic
596
        fun signatureIsOfType(vararg signatureType: SignatureType): SignatureValidator {
597
            return object : SignatureValidator() {
1✔
598
                override fun verify(signature: PGPSignature) {
599
                    if (signatureType.none { signature.isOfType(it) }) {
1✔
600
                        throw SignatureValidationException(
1✔
601
                            "Signature is of type" +
602
                                " ${SignatureType.fromCode(signature.signatureType) ?:
1✔
603
                                ("0x" + signature.signatureType.toString(16))}, " +
×
604
                                "while only ${signatureType.contentToString()} are allowed here.")
1✔
605
                    }
606
                }
1✔
607
            }
608
        }
609

610
        /**
611
         * Verify that a signature over a user-id is correct.
612
         *
613
         * @param userId user-id
614
         * @param certifiedKey key carrying the user-id
615
         * @param certifyingKey key that created the signature.
616
         * @return validator
617
         */
618
        @JvmStatic
619
        fun correctSignatureOverUserId(
620
            userId: CharSequence,
621
            certifiedKey: PGPPublicKey,
622
            certifyingKey: PGPPublicKey
623
        ): SignatureValidator {
624
            return object : SignatureValidator() {
1✔
625
                override fun verify(signature: PGPSignature) {
626
                    try {
1✔
627
                        signature.init(
1✔
628
                            ImplementationFactory.getInstance().pgpContentVerifierBuilderProvider,
1✔
629
                            certifyingKey)
1✔
630
                        if (!signature.verifyCertification(userId.toString(), certifiedKey)) {
1✔
631
                            throw SignatureValidationException(
1✔
632
                                "Signature over user-id '$userId' is not valid.")
1✔
633
                        }
634
                    } catch (e: PGPException) {
1✔
635
                        throw SignatureValidationException(
1✔
636
                            "Cannot verify signature over user-id '$userId'.", e)
1✔
637
                    } catch (e: ClassCastException) {
×
638
                        throw SignatureValidationException(
×
639
                            "Cannot verify signature over user-id '$userId'.", e)
×
640
                    }
641
                }
1✔
642
            }
643
        }
644

645
        /**
646
         * Verify that a signature over a user-attribute packet is correct.
647
         *
648
         * @param userAttributes user attributes
649
         * @param certifiedKey key carrying the user-attributes
650
         * @param certifyingKey key that created the certification signature
651
         * @return validator
652
         */
653
        @JvmStatic
654
        fun correctSignatureOverUserAttributes(
655
            userAttributes: PGPUserAttributeSubpacketVector,
656
            certifiedKey: PGPPublicKey,
657
            certifyingKey: PGPPublicKey
658
        ): SignatureValidator {
659
            return object : SignatureValidator() {
1✔
660
                override fun verify(signature: PGPSignature) {
661
                    try {
1✔
662
                        signature.init(
1✔
663
                            ImplementationFactory.getInstance().pgpContentVerifierBuilderProvider,
1✔
664
                            certifyingKey)
1✔
665
                        if (!signature.verifyCertification(userAttributes, certifiedKey)) {
1✔
666
                            throw SignatureValidationException(
1✔
667
                                "Signature over user-attributes is not correct.")
1✔
668
                        }
669
                    } catch (e: PGPException) {
1✔
670
                        throw SignatureValidationException(
1✔
671
                            "Cannot verify signature over user-attribute vector.", e)
1✔
672
                    } catch (e: ClassCastException) {
×
673
                        throw SignatureValidationException(
×
674
                            "Cannot verify signature over user-attribute vector.", e)
×
675
                    }
676
                }
1✔
677
            }
678
        }
679

680
        @JvmStatic
681
        fun signatureWasCreatedInBounds(notBefore: Date?, notAfter: Date?): SignatureValidator {
682
            return object : SignatureValidator() {
1✔
683
                override fun verify(signature: PGPSignature) {
684
                    val timestamp = signature.creationTime
1✔
685
                    if (notBefore != null && timestamp < notBefore) {
1✔
686
                        throw SignatureValidationException(
1✔
687
                            "Signature was made before the earliest allowed signature creation time." +
688
                                " Created: ${timestamp.formatUTC()}," +
1✔
689
                                " earliest allowed: ${notBefore.formatUTC()}")
1✔
690
                    }
691
                    if (notAfter != null && timestamp > notAfter) {
1✔
692
                        throw SignatureValidationException(
1✔
693
                            "Signature was made after the latest allowed signature creation time." +
694
                                " Created: ${timestamp.formatUTC()}," +
1✔
695
                                " latest allowed: ${notAfter.formatUTC()}")
1✔
696
                    }
697
                }
1✔
698
            }
699
        }
700
    }
701
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc