@@ -31,6 +31,7 @@ import java.security.MessageDigest
3131import java .security .PrivateKey
3232import java .security .SignatureException
3333import java .security .cert .X509Certificate
34+ import java .security .interfaces .RSAPublicKey
3435import java .util .Optional
3536
3637import com .fasterxml .jackson .databind .JsonNode
@@ -59,6 +60,7 @@ import com.yubico.webauthn.exception.RegistrationFailedException
5960import com .yubico .webauthn .test .Util .toStepWithUtilities
6061import com .yubico .webauthn .TestAuthenticator .AttestationCert
6162import com .yubico .webauthn .TestAuthenticator .AttestationMaker
63+ import com .yubico .webauthn .data .PublicKeyCredentialParameters
6264import javax .security .auth .x500 .X500Principal
6365import org .bouncycastle .asn1 .DEROctetString
6466import org .bouncycastle .asn1 .x500 .X500Name
@@ -1084,6 +1086,16 @@ class RelyingPartyRegistrationSpec extends FunSpec with Matchers with GeneratorD
10841086 result should equal (Success (true ))
10851087 }
10861088
1089+ it(" Succeeds for an RS1 test case." ) {
1090+ val testData = RegistrationTestData .Packed .BasicAttestationRs1
1091+
1092+ val result = verifier.verifyAttestationSignature(
1093+ new AttestationObject (testData.attestationObject),
1094+ testData.clientDataJsonHash
1095+ )
1096+ result should equal (true )
1097+ }
1098+
10871099 it(" Fail if the default test case is mutated." ) {
10881100 val testData = RegistrationTestData .Packed .BasicAttestation
10891101
@@ -1218,14 +1230,33 @@ class RelyingPartyRegistrationSpec extends FunSpec with Matchers with GeneratorD
12181230 }
12191231
12201232 it(" Fails if the alg is a different value." ) {
1221- val testData = RegistrationTestData .Packed .SelfAttestationWithWrongAlgValue
1233+ def modifyAuthdataPubkeyAlg (authDataBytes : Array [Byte ]): Array [Byte ] = {
1234+ val authData = new AuthenticatorData (new ByteArray (authDataBytes))
1235+ val key = WebAuthnCodecs .importCosePublicKey(authData.getAttestedCredentialData.get.getCredentialPublicKey).asInstanceOf [RSAPublicKey ]
1236+ val reencodedKey = WebAuthnTestCodecs .rsaPublicKeyToCose(key, COSEAlgorithmIdentifier .RS256 )
1237+ new ByteArray (java.util.Arrays .copyOfRange(authDataBytes, 0 , 32 + 1 + 4 + 16 + 2 ))
1238+ .concat(authData.getAttestedCredentialData.get.getCredentialId)
1239+ .concat(reencodedKey)
1240+ .getBytes
1241+ }
1242+ def modifyAttobjPubkeyAlg (attObjBytes : ByteArray ): ByteArray = {
1243+ val attObj = JacksonCodecs .cbor.readTree(attObjBytes.getBytes)
1244+ new ByteArray (JacksonCodecs .cbor.writeValueAsBytes(
1245+ attObj.asInstanceOf [ObjectNode ]
1246+ .set(" authData" , jsonFactory.binaryNode(modifyAuthdataPubkeyAlg(attObj.get(" authData" ).binaryValue())))
1247+ ))
1248+ }
1249+
1250+ val testData = RegistrationTestData .Packed .SelfAttestationRs1
1251+ val attObj = new AttestationObject (modifyAttobjPubkeyAlg(testData.response.getResponse.getAttestationObject))
1252+
12221253 val result = Try (verifier.verifyAttestationSignature(
1223- new AttestationObject (testData.attestationObject) ,
1254+ attObj ,
12241255 testData.clientDataJsonHash
12251256 ))
12261257
1227- CBORObject .DecodeFromBytes (new AttestationObject (testData.attestationObject). getAuthenticatorData.getAttestedCredentialData.get.getCredentialPublicKey.getBytes).get(CBORObject .FromObject (3 )).AsInt64 should equal (- 7 )
1228- new AttestationObject (testData.attestationObject). getAttestationStatement.get(" alg" ).longValue should equal (- 257 )
1258+ CBORObject .DecodeFromBytes (attObj. getAuthenticatorData.getAttestedCredentialData.get.getCredentialPublicKey.getBytes).get(CBORObject .FromObject (3 )).AsInt64 should equal (- 257 )
1259+ attObj. getAttestationStatement.get(" alg" ).longValue should equal (- 65535 )
12291260 result shouldBe a [Failure [_]]
12301261 result.failed.get shouldBe an [IllegalArgumentException ]
12311262 }
@@ -1240,6 +1271,18 @@ class RelyingPartyRegistrationSpec extends FunSpec with Matchers with GeneratorD
12401271 result should equal (true )
12411272 }
12421273
1274+ it(" Succeeds for an RS1 test case." ) {
1275+ val testData = RegistrationTestData .Packed .SelfAttestationRs1
1276+ val alg = WebAuthnCodecs .getCoseKeyAlg(testData.response.getResponse.getParsedAuthenticatorData.getAttestedCredentialData.get.getCredentialPublicKey).get
1277+ alg should be (COSEAlgorithmIdentifier .RS1 )
1278+
1279+ val result = verifier.verifyAttestationSignature(
1280+ new AttestationObject (testData.attestationObject),
1281+ testData.clientDataJsonHash
1282+ )
1283+ result should equal (true )
1284+ }
1285+
12431286 it(" Fails if the attestation object is mutated." ) {
12441287 val testData = testDataBase.editAuthenticatorData { authData : ByteArray => new ByteArray (authData.getBytes.updated(16 , if (authData.getBytes()(16 ) == 0 ) 1 : Byte else 0 : Byte )) }
12451288 val result = verifier.verifyAttestationSignature(
@@ -1934,7 +1977,7 @@ class RelyingPartyRegistrationSpec extends FunSpec with Matchers with GeneratorD
19341977 }
19351978
19361979 describe(" accept all test examples in the validExamples list." ) {
1937- RegistrationTestData .validExamples .zipWithIndex.foreach { case (testData, i) =>
1980+ RegistrationTestData .defaultSettingsValidExamples .zipWithIndex.foreach { case (testData, i) =>
19381981 it(s " Succeeds for example index ${i}. " ) {
19391982 val rp = {
19401983 val builder = RelyingParty .builder()
@@ -1954,6 +1997,46 @@ class RelyingPartyRegistrationSpec extends FunSpec with Matchers with GeneratorD
19541997 }
19551998 }
19561999 }
2000+
2001+ describe(" generate pubKeyCredParams which" ) {
2002+ val rp = RelyingParty .builder()
2003+ .identity(RelyingPartyIdentity .builder().id(" localhost" ).name(" Test RP" ).build())
2004+ .credentialRepository(emptyCredentialRepository)
2005+ .build()
2006+ val pkcco = rp.startRegistration(StartRegistrationOptions .builder()
2007+ .user(UserIdentity .builder()
2008+ .name(" foo" )
2009+ .displayName(" Foo" )
2010+ .id(ByteArray .fromHex(" aabbccdd" ))
2011+ .build())
2012+ .build())
2013+
2014+ val pubKeyCredParams = pkcco.getPubKeyCredParams.asScala
2015+
2016+ describe(" include" ) {
2017+ it(" ES256." ) {
2018+ pubKeyCredParams should contain (PublicKeyCredentialParameters .ES256 )
2019+ pubKeyCredParams map (_.getAlg) should contain (COSEAlgorithmIdentifier .ES256 )
2020+ }
2021+
2022+ it(" EdDSA." ) {
2023+ pubKeyCredParams should contain (PublicKeyCredentialParameters .EdDSA )
2024+ pubKeyCredParams map (_.getAlg) should contain (COSEAlgorithmIdentifier .EdDSA )
2025+ }
2026+
2027+ it(" RS256." ) {
2028+ pubKeyCredParams should contain (PublicKeyCredentialParameters .RS256 )
2029+ pubKeyCredParams map (_.getAlg) should contain (COSEAlgorithmIdentifier .RS256 )
2030+ }
2031+ }
2032+
2033+ describe(" do not include" ) {
2034+ it(" RS1." ) {
2035+ pubKeyCredParams should not contain PublicKeyCredentialParameters .RS1
2036+ pubKeyCredParams map (_.getAlg) should not contain COSEAlgorithmIdentifier .RS1
2037+ }
2038+ }
2039+ }
19572040 }
19582041
19592042 describe(" RelyingParty supports registering" ) {
0 commit comments