Esempio n. 1
0
        public async Task <string> AuthenticateRequests(SecurityKeyAuthenticateRequest[] requests)
        {
            if (requests == null || requests.Length == 0)
            {
                throw new KeeperCanceled();
            }
            var cancellationSource = new CancellationTokenSource();
            var clientData         = new SecurityKeyClientData
            {
                dataType  = SecurityKeyClientData.U2F_SIGN,
                challenge = requests[0].challenge,
                origin    = requests[0].appId,
            };
            var keyHandles = new List <byte[]>
            {
                requests[0].keyHandle.Base64UrlDecode()
            };

            foreach (var rq in requests.Skip(1))
            {
                if (rq.challenge == clientData.challenge && rq.appId == clientData.origin)
                {
                    keyHandles.Add(rq.keyHandle.Base64UrlDecode());
                }
            }

            var u2fSignature = await WinWebAuthn.Authenticate.GetAssertion(WinWebAuthn.Authenticate.GetConsoleWindow(), clientData, keyHandles, cancellationSource.Token);

            var signature = new SecurityKeySignature
            {
                clientData    = u2fSignature.clientData.Base64UrlEncode(),
                signatureData = u2fSignature.signatureData.Base64UrlEncode(),
                keyHandle     = u2fSignature.keyHandle.Base64UrlEncode()
            };

            return(Encoding.UTF8.GetString(JsonUtils.DumpJson(signature)));
        }
        public static Task <U2FSignature> GetAssertion(IntPtr hWnd, SecurityKeyClientData clientData, IList <byte[]> keyHandles, CancellationToken token)
        {
            var taskSource = new TaskCompletionSource <U2FSignature>();

            Task.Run(() =>
            {
                var ptrList = new List <IntPtr>();
                try
                {
                    var clientDataBytes = JsonUtils.DumpJson(clientData);
                    var clientDataPtr   = Marshal.AllocHGlobal(clientDataBytes.Length);
                    ptrList.Add(clientDataPtr);
                    Marshal.Copy(clientDataBytes, 0, clientDataPtr, clientDataBytes.Length);

                    var data = new NativeWebAuthn.WEBAUTHN_CLIENT_DATA
                    {
                        dwVersion        = NativeWebAuthn.WEBAUTHN_API_VERSION_2,
                        cbClientDataJSON = clientDataBytes.Length,
                        pbClientDataJSON = clientDataPtr,
                        pwszHashAlgId    = NativeWebAuthn.WEBAUTHN_HASH_ALGORITHM_SHA_256,
                    };

                    var credentialSize = Marshal.SizeOf(typeof(NativeWebAuthn.WEBAUTHN_CREDENTIAL));
                    var credentialsPtr = Marshal.AllocHGlobal(keyHandles.Count * credentialSize);
                    ptrList.Add(credentialsPtr);
                    var pubKeyPtr = Marshal.StringToHGlobalUni(NativeWebAuthn.WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY);
                    ptrList.Add(pubKeyPtr);
                    for (var i = 0; i < keyHandles.Count; i++)
                    {
                        var credLength = keyHandles[i].Length;
                        var credPtr    = Marshal.AllocHGlobal(credLength);
                        ptrList.Add(credPtr);
                        Marshal.Copy(keyHandles[i], 0, credPtr, credLength);
                        var cred = new NativeWebAuthn.WEBAUTHN_CREDENTIAL
                        {
                            dwVersion          = NativeWebAuthn.WEBAUTHN_CREDENTIAL_CURRENT_VERSION,
                            cbId               = credLength,
                            pbId               = credPtr,
                            pwszCredentialType = pubKeyPtr
                        };
                        Marshal.StructureToPtr(cred, credentialsPtr, false);
                    }

                    var opts = new NativeWebAuthn.WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS
                    {
                        dwVersion             = 4,
                        dwTimeoutMilliseconds = (uint)TimeSpan.FromMinutes(2).TotalMilliseconds,
                        CredentialList        = new NativeWebAuthn.WEBAUTHN_CREDENTIALS
                        {
                            cCredentials = keyHandles.Count,
                            pCredentials = credentialsPtr
                        },
                        Extensions = new NativeWebAuthn.WEBAUTHN_EXTENSIONS
                        {
                            cExtensions = 0,
                            pExtensions = IntPtr.Zero
                        },
                        dwAuthenticatorAttachment     = NativeWebAuthn.WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2,
                        dwUserVerificationRequirement = 0,
                        dwFlags              = 0,
                        pwszU2fAppId         = IntPtr.Zero,
                        pbU2fAppId           = IntPtr.Zero,
                        pCancellationId      = IntPtr.Zero,
                        pAllowCredentialList = IntPtr.Zero,
                    };

                    IDisposable cancelToken = null;
                    if (token != CancellationToken.None)
                    {
                        var guidPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(GuidClass)));
                        ptrList.Add(guidPtr);
                        if (NativeWebAuthn.WebAuthNGetCancellationId(guidPtr) == NativeWebAuthn.HRESULT.S_OK)
                        {
                            opts.pCancellationId = guidPtr;
                            cancelToken          = token.Register(() => { NativeWebAuthn.WebAuthNCancelCurrentOperation(guidPtr); });
                        }
                    }

                    var hr = NativeWebAuthn.WebAuthNAuthenticatorGetAssertion(hWnd, clientData.origin, ref data, ref opts, out var assertionPtr);
                    cancelToken?.Dispose();

                    if (hr == NativeWebAuthn.HRESULT.S_OK)
                    {
                        var assertion = (NativeWebAuthn.WEBAUTHN_ASSERTION)Marshal.PtrToStructure(assertionPtr, typeof(NativeWebAuthn.WEBAUTHN_ASSERTION));

                        byte[] keyHandleBytes;
                        if (assertion.Credential.cbId > 0)
                        {
                            keyHandleBytes = new byte[assertion.Credential.cbId];
                            if (assertion.Credential.pbId != IntPtr.Zero)
                            {
                                Marshal.Copy(assertion.Credential.pbId, keyHandleBytes, 0, assertion.Credential.cbId);
                            }
                        }
                        else
                        {
                            keyHandleBytes = new byte[0];
                        }

                        byte[] authenticatorData;
                        if (assertion.cbAuthenticatorData > 0)
                        {
                            authenticatorData = new byte[assertion.cbAuthenticatorData];
                            if (assertion.pbAuthenticatorData != IntPtr.Zero)
                            {
                                Marshal.Copy(assertion.pbAuthenticatorData, authenticatorData, 0, assertion.cbAuthenticatorData);
                            }
                        }
                        else
                        {
                            authenticatorData = new byte[0];
                        }

                        byte[] signatureBytes;
                        if (assertion.cbSignature > 0)
                        {
                            signatureBytes = new byte[assertion.cbSignature];
                            if (assertion.pbSignature != IntPtr.Zero)
                            {
                                Marshal.Copy(assertion.pbSignature, signatureBytes, 0, assertion.cbSignature);
                            }
                        }
                        else
                        {
                            signatureBytes = new byte[0];
                        }

                        NativeWebAuthn.WebAuthNFreeAssertion(assertionPtr);
                        taskSource.TrySetResult(new U2FSignature
                        {
                            clientData    = clientDataBytes,
                            signatureData = authenticatorData.Skip(32).Take(5).Concat(signatureBytes).ToArray(),
                            keyHandle     = keyHandleBytes
                        });
                    }
                    else
                    {
                        var ptr   = NativeWebAuthn.WebAuthNGetErrorName(hr);
                        var error = Marshal.PtrToStringUni(ptr);
                        taskSource.SetException(new Exception($"WebauthN GetAssertion error: {error}"));
                    }
                }
                finally
                {
                    foreach (var ptr in ptrList)
                    {
                        Marshal.FreeHGlobal(ptr);
                    }

                    ptrList.Clear();
                }
            },
                     token);

            return(taskSource.Task);
        }
 public static Task <U2FSignature> GetAssertion(IntPtr hWnd, SecurityKeyClientData clientData, IList <byte[]> keyHandles)
 {
     return(GetAssertion(hWnd, clientData, keyHandles, CancellationToken.None));
 }