1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.credentials.webauthn 18 19 import androidx.annotation.RestrictTo 20 import java.security.MessageDigest 21 import org.json.JSONObject 22 23 @RestrictTo(RestrictTo.Scope.LIBRARY) 24 class AuthenticatorAssertionResponse( 25 private val requestOptions: PublicKeyCredentialRequestOptions, 26 private val credentialId: ByteArray, 27 private val origin: String, 28 private val up: Boolean, 29 private val uv: Boolean, 30 private val be: Boolean, 31 private val bs: Boolean, 32 private var userHandle: ByteArray, 33 private val packageName: String? = null, 34 private val clientDataHash: ByteArray? = null, 35 ) : AuthenticatorResponse { 36 override var clientJson = JSONObject() 37 var authenticatorData: ByteArray 38 var signature: ByteArray = byteArrayOf() 39 40 init { 41 clientJson.put("type", "webauthn.get") 42 clientJson.put("challenge", WebAuthnUtils.b64Encode(requestOptions.challenge)) 43 clientJson.put("origin", origin) 44 if (packageName != null) { 45 clientJson.put("androidPackageName", packageName) 46 } 47 48 authenticatorData = defaultAuthenticatorData() 49 } 50 defaultAuthenticatorDatanull51 fun defaultAuthenticatorData(): ByteArray { 52 val md = MessageDigest.getInstance("SHA-256") 53 val rpHash = md.digest(requestOptions.rpId.toByteArray()) 54 var flags: Int = 0 55 if (up) { 56 flags = flags or 0x01 57 } 58 if (uv) { 59 flags = flags or 0x04 60 } 61 if (be) { 62 flags = flags or 0x08 63 } 64 if (bs) { 65 flags = flags or 0x10 66 } 67 val ret = rpHash + byteArrayOf(flags.toByte()) + byteArrayOf(0, 0, 0, 0) 68 return ret 69 } 70 dataToSignnull71 fun dataToSign(): ByteArray { 72 val md = MessageDigest.getInstance("SHA-256") 73 var hash: ByteArray 74 if (clientDataHash != null) { 75 hash = clientDataHash 76 } else { 77 hash = md.digest(clientJson.toString().toByteArray()) 78 } 79 80 return authenticatorData + hash 81 } 82 jsonnull83 override fun json(): JSONObject { 84 val clientData = clientJson.toString().toByteArray() 85 val response = JSONObject() 86 if (clientDataHash == null) { 87 response.put("clientDataJSON", WebAuthnUtils.b64Encode(clientData)) 88 } 89 response.put("authenticatorData", WebAuthnUtils.b64Encode(authenticatorData)) 90 response.put("signature", WebAuthnUtils.b64Encode(signature)) 91 response.put("userHandle", WebAuthnUtils.b64Encode(userHandle)) 92 return response 93 } 94 } 95