Skip to content

Commit 0a6e32f

Browse files
authored
Merge pull request #482 from Yubico/regenerate-rs1
Make TestAuthenticator.createAuthenticatorData harder to call incorrectly
2 parents 5ebcf31 + 0313fbd commit 0a6e32f

5 files changed

Lines changed: 72 additions & 52 deletions

File tree

webauthn-server-core/build.gradle.kts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,13 @@ tasks.withType(Jar::class) {
6666
))
6767
}
6868
}
69+
70+
tasks.register<JavaExec>("regenerateTestData") {
71+
classpath = sourceSets.test.get().runtimeClasspath
72+
mainClass = "com.yubico.webauthn.RegistrationTestDataGenerator"
73+
description = "Generate code to paste into RegistrationTestData.scala"
74+
group = "development"
75+
javaLauncher.set(javaToolchains.launcherFor {
76+
languageVersion.set(JavaLanguageVersion.of(25))
77+
})
78+
}

webauthn-server-core/src/test/scala/com/yubico/webauthn/RegistrationTestData.scala

Lines changed: 42 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ import org.bouncycastle.asn1.x500.X500Name
5959
import org.bouncycastle.asn1.x509.Extension
6060
import org.bouncycastle.asn1.x509.GeneralName
6161
import org.bouncycastle.asn1.x509.GeneralNamesBuilder
62+
import org.junit.runner.RunWith
63+
import org.scalatest.funspec.AnyFunSpec
64+
import org.scalatestplus.junit.JUnitRunner
6265

6366
import java.nio.charset.StandardCharsets
6467
import java.security.KeyFactory
@@ -68,10 +71,8 @@ import java.security.cert.X509Certificate
6871
import java.security.spec.PKCS8EncodedKeySpec
6972
import scala.jdk.CollectionConverters._
7073
import scala.jdk.OptionConverters.RichOption
71-
import scala.util.Failure
72-
import scala.util.Success
73-
import scala.util.Try
7474

75+
/** Run using IDE or `./gradlew regenerateTestData` */
7576
object RegistrationTestDataGenerator extends App {
7677
regenerateTestData()
7778

@@ -162,14 +163,8 @@ object RegistrationTestDataGenerator extends App {
162163
td.Tpm.ValidRs1,
163164
).zipWithIndex
164165
} {
165-
testData.regenerateFull() match {
166-
case Success(newTestData) =>
167-
println(i)
168-
printTestDataCode(newTestData)
169-
case Failure(e) =>
170-
println("Failed to regenerate")
171-
e.printStackTrace()
172-
}
166+
println(i)
167+
printTestDataCode(testData.regenerateFull())
173168
}
174169
}
175170
}
@@ -440,7 +435,7 @@ object RegistrationTestData {
440435
) {
441436
override def regenerate() =
442437
TestAuthenticator.createBasicAttestedCredential(
443-
keyAlgorithm = COSEAlgorithmIdentifier.EdDSA,
438+
keyAlgorithm = Some(COSEAlgorithmIdentifier.EdDSA),
444439
attestationMaker = AttestationMaker.packed(
445440
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ES256)
446441
),
@@ -477,7 +472,7 @@ object RegistrationTestData {
477472
) {
478473
override def regenerate() =
479474
TestAuthenticator.createBasicAttestedCredential(
480-
keyAlgorithm = COSEAlgorithmIdentifier.Ed448,
475+
keyAlgorithm = Some(COSEAlgorithmIdentifier.Ed448),
481476
attestationMaker = AttestationMaker.packed(
482477
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ES256)
483478
),
@@ -515,7 +510,7 @@ object RegistrationTestData {
515510
) {
516511
override def regenerate() =
517512
TestAuthenticator.createBasicAttestedCredential(
518-
keyAlgorithm = COSEAlgorithmIdentifier.ML_DSA_44,
513+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ML_DSA_44),
519514
attestationMaker = AttestationMaker.packed(
520515
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ML_DSA_44)
521516
),
@@ -553,7 +548,7 @@ object RegistrationTestData {
553548
) {
554549
override def regenerate() =
555550
TestAuthenticator.createBasicAttestedCredential(
556-
keyAlgorithm = COSEAlgorithmIdentifier.ML_DSA_65,
551+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ML_DSA_65),
557552
attestationMaker = AttestationMaker.packed(
558553
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ML_DSA_65)
559554
),
@@ -591,7 +586,7 @@ object RegistrationTestData {
591586
) {
592587
override def regenerate() =
593588
TestAuthenticator.createBasicAttestedCredential(
594-
keyAlgorithm = COSEAlgorithmIdentifier.ML_DSA_87,
589+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ML_DSA_87),
595590
attestationMaker = AttestationMaker.packed(
596591
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ML_DSA_87)
597592
),
@@ -616,7 +611,7 @@ object RegistrationTestData {
616611
) {
617612
override def regenerate() =
618613
TestAuthenticator.createBasicAttestedCredential(
619-
keyAlgorithm = COSEAlgorithmIdentifier.RS256,
614+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS256),
620615
attestationMaker = AttestationMaker.packed(
621616
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS256)
622617
),
@@ -641,7 +636,7 @@ object RegistrationTestData {
641636
) {
642637
override def regenerate() =
643638
TestAuthenticator.createBasicAttestedCredential(
644-
keyAlgorithm = COSEAlgorithmIdentifier.RS384,
639+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS384),
645640
attestationMaker = AttestationMaker.packed(
646641
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS384)
647642
),
@@ -666,7 +661,7 @@ object RegistrationTestData {
666661
) {
667662
override def regenerate() =
668663
TestAuthenticator.createBasicAttestedCredential(
669-
keyAlgorithm = COSEAlgorithmIdentifier.RS512,
664+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS512),
670665
attestationMaker = AttestationMaker.packed(
671666
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS512)
672667
),
@@ -703,7 +698,7 @@ object RegistrationTestData {
703698
) {
704699
override def regenerate() =
705700
TestAuthenticator.createBasicAttestedCredential(
706-
keyAlgorithm = COSEAlgorithmIdentifier.RS1,
701+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS1),
707702
attestationMaker = AttestationMaker.packed(
708703
AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS1)
709704
),
@@ -947,7 +942,7 @@ object RegistrationTestData {
947942
) {
948943
override def regenerate() =
949944
TestAuthenticator.createBasicAttestedCredential(
950-
keyAlgorithm = COSEAlgorithmIdentifier.ES256,
945+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES256),
951946
attestationMaker = AttestationMaker.tpm(
952947
AttestationSigner.ca(
953948
alg = COSEAlgorithmIdentifier.ES256,
@@ -980,7 +975,7 @@ object RegistrationTestData {
980975
) {
981976
override def regenerate() =
982977
TestAuthenticator.createBasicAttestedCredential(
983-
keyAlgorithm = COSEAlgorithmIdentifier.ES256,
978+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES256),
984979
attestationMaker = AttestationMaker.tpm(
985980
AttestationSigner.ca(
986981
alg = COSEAlgorithmIdentifier.ES256,
@@ -1013,7 +1008,7 @@ object RegistrationTestData {
10131008
) {
10141009
override def regenerate() =
10151010
TestAuthenticator.createBasicAttestedCredential(
1016-
keyAlgorithm = COSEAlgorithmIdentifier.ES384,
1011+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES384),
10171012
attestationMaker = AttestationMaker.tpm(
10181013
AttestationSigner.ca(
10191014
alg = COSEAlgorithmIdentifier.ES384,
@@ -1046,7 +1041,7 @@ object RegistrationTestData {
10461041
) {
10471042
override def regenerate() =
10481043
TestAuthenticator.createBasicAttestedCredential(
1049-
keyAlgorithm = COSEAlgorithmIdentifier.ES512,
1044+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES512),
10501045
attestationMaker = AttestationMaker.tpm(
10511046
AttestationSigner.ca(
10521047
alg = COSEAlgorithmIdentifier.ES512,
@@ -1080,7 +1075,7 @@ object RegistrationTestData {
10801075
) {
10811076
override def regenerate() =
10821077
TestAuthenticator.createBasicAttestedCredential(
1083-
keyAlgorithm = COSEAlgorithmIdentifier.RS256,
1078+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS256),
10841079
attestationMaker = AttestationMaker.tpm(
10851080
AttestationSigner.ca(
10861081
alg = COSEAlgorithmIdentifier.RS256,
@@ -1114,7 +1109,7 @@ object RegistrationTestData {
11141109
) {
11151110
override def regenerate() =
11161111
TestAuthenticator.createBasicAttestedCredential(
1117-
keyAlgorithm = COSEAlgorithmIdentifier.RS384,
1112+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS384),
11181113
attestationMaker = AttestationMaker.tpm(
11191114
AttestationSigner.ca(
11201115
alg = COSEAlgorithmIdentifier.RS384,
@@ -1148,7 +1143,7 @@ object RegistrationTestData {
11481143
) {
11491144
override def regenerate() =
11501145
TestAuthenticator.createBasicAttestedCredential(
1151-
keyAlgorithm = COSEAlgorithmIdentifier.RS512,
1146+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS512),
11521147
attestationMaker = AttestationMaker.tpm(
11531148
AttestationSigner.ca(
11541149
alg = COSEAlgorithmIdentifier.RS512,
@@ -1182,7 +1177,7 @@ object RegistrationTestData {
11821177
) {
11831178
override def regenerate() =
11841179
TestAuthenticator.createBasicAttestedCredential(
1185-
keyAlgorithm = COSEAlgorithmIdentifier.RS1,
1180+
keyAlgorithm = Some(COSEAlgorithmIdentifier.RS1),
11861181
attestationMaker = AttestationMaker.tpm(
11871182
AttestationSigner.ca(
11881183
alg = COSEAlgorithmIdentifier.RS1,
@@ -1252,15 +1247,14 @@ case class RegistrationTestData(
12521247
KeyPair,
12531248
List[(X509Certificate, PrivateKey)],
12541249
) = ???
1255-
def regenerateFull(): Try[RegistrationTestData] =
1256-
Try({
1257-
val (credential, keypair, attestationCertChain) = regenerate()
1258-
val newValue =
1259-
RegistrationTestData.from(credential, keypair, attestationCertChain)
1260-
newValue.copy(
1261-
assertion = assertion.map(_.regenerate(newValue))
1262-
)
1263-
})
1250+
def regenerateFull(): RegistrationTestData = {
1251+
val (credential, keypair, attestationCertChain) = regenerate()
1252+
val newValue =
1253+
RegistrationTestData.from(credential, keypair, attestationCertChain)
1254+
newValue.copy(
1255+
assertion = assertion.map(_.regenerate(newValue))
1256+
)
1257+
}
12641258

12651259
protected def validate(): Unit = {
12661260
val alg = COSEAlgorithmIdentifier
@@ -1443,3 +1437,14 @@ case class AssertionTestData(
14431437
)
14441438
}
14451439
}
1440+
1441+
@RunWith(classOf[JUnitRunner])
1442+
class RegistrationTestDataSpec extends AnyFunSpec {
1443+
describe("RegistrationTestDataGenerator") {
1444+
it("successfully regenerates all test cases.") {
1445+
assume(Util.eddsaAvailable)
1446+
assume(Util.mldsaAvailable)
1447+
RegistrationTestDataGenerator.regenerateTestData()
1448+
}
1449+
}
1450+
}

webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyRegistrationSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,7 +2363,7 @@ class RelyingPartyRegistrationSpec
23632363
credKeyAlgorithm
23642364
)
23652365
),
2366-
keyAlgorithm = credKeyAlgorithm,
2366+
keyAlgorithm = Some(credKeyAlgorithm),
23672367
)
23682368
)
23692369

@@ -2537,7 +2537,7 @@ class RelyingPartyRegistrationSpec
25372537
it("Fails when EC key has an inverted Y coordinate.") {
25382538
val (authData, keypair) =
25392539
TestAuthenticator.createAuthenticatorData(keyAlgorithm =
2540-
COSEAlgorithmIdentifier.ES256
2540+
Some(COSEAlgorithmIdentifier.ES256)
25412541
)
25422542

25432543
val cose = CBORObject.DecodeFromBytes(
@@ -2576,7 +2576,7 @@ class RelyingPartyRegistrationSpec
25762576
it("Fails when RSA key is unrelated.") {
25772577
val (authData, keypair) =
25782578
TestAuthenticator.createAuthenticatorData(keyAlgorithm =
2579-
COSEAlgorithmIdentifier.RS256
2579+
Some(COSEAlgorithmIdentifier.RS256)
25802580
)
25812581
val testData = (RegistrationTestData.from _).tupled(
25822582
makeCred(
@@ -2856,7 +2856,7 @@ class RelyingPartyRegistrationSpec
28562856
) {
28572857
val testData = (RegistrationTestData.from _).tupled(
28582858
TestAuthenticator.createBasicAttestedCredential(
2859-
keyAlgorithm = COSEAlgorithmIdentifier.ES256,
2859+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES256),
28602860
attestationMaker = AttestationMaker.tpm(
28612861
AttestationSigner.selfsigned(
28622862
alg = COSEAlgorithmIdentifier.ES256,

webauthn-server-core/src/test/scala/com/yubico/webauthn/RelyingPartyV2RegistrationSpec.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,7 +2314,7 @@ class RelyingPartyV2RegistrationSpec
23142314
credKeyAlgorithm
23152315
)
23162316
),
2317-
keyAlgorithm = credKeyAlgorithm,
2317+
keyAlgorithm = Some(credKeyAlgorithm),
23182318
)
23192319
)
23202320

@@ -2488,7 +2488,7 @@ class RelyingPartyV2RegistrationSpec
24882488
it("Fails when EC key has an inverted Y coordinate.") {
24892489
val (authData, keypair) =
24902490
TestAuthenticator.createAuthenticatorData(keyAlgorithm =
2491-
COSEAlgorithmIdentifier.ES256
2491+
Some(COSEAlgorithmIdentifier.ES256)
24922492
)
24932493

24942494
val cose = CBORObject.DecodeFromBytes(
@@ -2527,7 +2527,7 @@ class RelyingPartyV2RegistrationSpec
25272527
it("Fails when RSA key is unrelated.") {
25282528
val (authData, keypair) =
25292529
TestAuthenticator.createAuthenticatorData(keyAlgorithm =
2530-
COSEAlgorithmIdentifier.RS256
2530+
Some(COSEAlgorithmIdentifier.RS256)
25312531
)
25322532
val testData = (RegistrationTestData.from _).tupled(
25332533
makeCred(
@@ -2807,7 +2807,7 @@ class RelyingPartyV2RegistrationSpec
28072807
) {
28082808
val testData = (RegistrationTestData.from _).tupled(
28092809
TestAuthenticator.createBasicAttestedCredential(
2810-
keyAlgorithm = COSEAlgorithmIdentifier.ES256,
2810+
keyAlgorithm = Some(COSEAlgorithmIdentifier.ES256),
28112811
attestationMaker = AttestationMaker.tpm(
28122812
AttestationSigner.selfsigned(
28132813
alg = COSEAlgorithmIdentifier.ES256,

webauthn-server-core/src/test/scala/com/yubico/webauthn/TestAuthenticator.scala

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,21 +404,25 @@ object TestAuthenticator {
404404
aaguid: ByteArray = Defaults.aaguid,
405405
authenticatorExtensions: Option[JsonNode] = None,
406406
credentialKeypair: Option[KeyPair] = None,
407-
keyAlgorithm: COSEAlgorithmIdentifier = Defaults.keyAlgorithm,
407+
keyAlgorithm: Option[COSEAlgorithmIdentifier] = None,
408408
flags: Option[AuthenticatorDataFlags] = None,
409409
): (
410410
ByteArray,
411411
KeyPair,
412412
) = {
413413
val keypair =
414-
credentialKeypair.getOrElse(generateKeypair(algorithm = keyAlgorithm))
414+
credentialKeypair.getOrElse(
415+
generateKeypair(algorithm =
416+
keyAlgorithm.getOrElse(Defaults.keyAlgorithm)
417+
)
418+
)
415419
val publicKeyCose = keypair.getPublic match {
416420
case pub: ECPublicKey => WebAuthnTestCodecs.ecPublicKeyToCose(pub)
417421
case pub: BCEdDSAPublicKey => WebAuthnTestCodecs.eddsaPublicKeyToCose(pub)
418422
case pub: RSAPublicKey =>
419-
WebAuthnTestCodecs.rsaPublicKeyToCose(pub, keyAlgorithm)
423+
WebAuthnTestCodecs.rsaPublicKeyToCose(pub, keyAlgorithm.get)
420424
case pub if pub.getAlgorithm == "ML-DSA" =>
421-
WebAuthnTestCodecs.mlDsaPublicKeyToCose(pub, keyAlgorithm)
425+
WebAuthnTestCodecs.mlDsaPublicKeyToCose(pub, keyAlgorithm.get)
422426
}
423427

424428
val authDataBytes: ByteArray = makeAuthDataBytes(
@@ -516,7 +520,7 @@ object TestAuthenticator {
516520
def createBasicAttestedCredential(
517521
aaguid: ByteArray = Defaults.aaguid,
518522
attestationMaker: AttestationMaker,
519-
keyAlgorithm: COSEAlgorithmIdentifier = Defaults.keyAlgorithm,
523+
keyAlgorithm: Option[COSEAlgorithmIdentifier] = None,
520524
): (
521525
data.PublicKeyCredential[
522526
data.AuthenticatorAttestationResponse,
@@ -548,8 +552,9 @@ object TestAuthenticator {
548552
KeyPair,
549553
List[(X509Certificate, PrivateKey)],
550554
) = {
551-
val (authData, keypair) = createAuthenticatorData(credentialKeypair =
552-
Some(generateKeypair(keyAlgorithm))
555+
val (authData, keypair) = createAuthenticatorData(
556+
credentialKeypair = Some(generateKeypair(keyAlgorithm)),
557+
keyAlgorithm = Some(keyAlgorithm),
553558
)
554559
val signer = SelfAttestation(keypair, keyAlgorithm)
555560
createCredential(

0 commit comments

Comments
 (0)