Yubico / Yubico.NET.SDK

A YubiKey SDK for .NET developers
Apache License 2.0
101 stars 51 forks source link

Yubico.NativeShims breaks Powershell #32

Closed virot closed 6 months ago

virot commented 1 year ago

With the implementation of Yubico.NativeShims (1.3.0), it is no longer possible (I cant find a way) to use the SDK for work with Powershell (which is based on .NET).

I have no problem adding the other DLLs, but Yubico.NativeShims gives the error: (PS 7.3):

Add-Type: Bad IL format. The format of the file 'C:\temp\yubico.nativeshims.1.5.2\runtimes\win-x64\native\Yubico.NativeShims.dll' is invalid.

(PS 5.1):

Add-Type : Could not load file or assembly 'file:///C:\temp\yubico.nativeshims.1.5.2\runtimes\win-arm64\native\Yubico.N
ativeShims.dll' or one of its dependencies. The module was expected to contain an assembly manifest.
At line:1 char:1
+ Add-Type -Path C:\temp\yubico.nativeshims.1.5.2\runtimes\win-arm64\na ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Add-Type], BadImageFormatException
    + FullyQualifiedErrorId : System.BadImageFormatException,Microsoft.PowerShell.Commands.AddTypeCommand

This restricts usage of Yubico.Yubikey and Yubico.Core to version 1.2.0 or earlier.

GregDomzalski commented 1 year ago

Is this a compiled / DLL based PowerShell cmdlet? Or a script-based cmdlet?

PS 5.1 (based on .NET framework) is probably the same as #11.

PS 7.3 (which I believe is based on .NET core?)... This error is given when there's a platform / architecture mismatch. Are you sure you're running in a 64-bit process with your module compiled as 64-bit (and not something like 'AnyCPU'?)

I think I've finally made some progress tracking down what I hope to be a solution for this native dependency import problem that older .NET frameworks have been having. The next release should (hopefully, finally) have a fix for this issue.

virot commented 1 year ago

Script based.

Works

PS C:\temp> add-type -path .\yubico.core.1.5.1\lib\net47\Yubico.Core.dll I have tried all.. Even though I run x64 both OS and Powershell (.net) PS C:\temp> add-type -path .\yubico.nativeshims.1.5.2\runtimes\win-arm64\native\Yubico.NativeShims.dll Add-Type: Bad IL format. The format of the file 'C:\temp\yubico.nativeshims.1.5.2\runtimes\win-arm64\native\Yubico.NativeShims.dll' is invalid. PS C:\temp> add-type -path .\yubico.nativeshims.1.5.2\runtimes\win-x64\native\Yubico.NativeShims.dll Add-Type: Bad IL format. The format of the file 'C:\temp\yubico.nativeshims.1.5.2\runtimes\win-x64\native\Yubico.NativeShims.dll' is invalid. PS C:\temp> add-type -path .\yubico.nativeshims.1.5.2\runtimes\win-x86\native\Yubico.NativeShims.dll Add-Type: Bad IL format. The format of the file 'C:\temp\yubico.nativeshims.1.5.2\runtimes\win-x86\native\Yubico.NativeShims.dll' is invalid. PS C:\temp> $PSVersionTable

Name Value


PSVersion 7.3.0 PSEdition Core GitCommitId 7.3.0 OS Microsoft Windows 10.0.19044 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0

PS C:\temp>

GregDomzalski commented 1 year ago

Oh, hmm.

OK - that will take some more experimentation on my part. I don't think anyone on the team has tried using this from a script module yet.

I will let you know what I find out.

GregDomzalski commented 1 year ago

Hi @virot - sorry this has taken so long.

I originally though this might be related to #11 - however I realized that NuGet is probably not involved with your PowerShell project.

Am I correct in assuming that you were downloading the NuGet packages directly and then unpacking the assemblies by hand?

If that's the case, I recommend copying out all of the assemblies into a common dependency directory. Since Yubico.NativeShims is a native DLL, you should not use "Add-Type" to import it, as there is nothing to import. Instead, the Yubico.NativeShims DLL should be placed in the same directory as the Yubico.Core assembly.

Keep in mind that the version of Yubico.NativeShims that you copy must match the processor architecture of the running PowerShell process.

virot commented 1 year ago

Yes I am downloading the NuGet packages and unzipping. I just tried tried the 1.6.1 version:

virot commented 1 year ago

Will try the other way, by building a DLL module, but that will make it less easy to extend.

virot commented 1 year ago

I cant understand that NativeShims. I have created a supersimple repo with a Windows Powershell module DLL https://github.com/virot/powershell_yubikey.

If you build it will copy dlls etc.. It copies all DLLs required... Except NativeShims. Test-SampleCmdlet : Unable to load DLL 'Yubico.NativeShims': The specified module could not be found. (Exception from HRESULT: 0x8007007E) At line:1 char:1

Wondering if "Calling C# SDK from Python results in "Unable to load DLL 'Yubico.NativeShims'" error #47 is related, as that seems to be running powershell in python.

virot commented 1 year ago

I did the follwing comments in the wrong issue: https://github.com/Yubico/Yubico.NET.SDK/issues/47

Funny thing. The only places it seems to read is:

C:\Windows\System32\WindowsPowerShell\v1.0\Yubico.NativeShims C:\Windows\System32\Yubico.NativeShims So I copied it to C:\Windows\System32\WindowsPowerShell\v1.0\Yubico.NativeShims without .dll, otherwise it doesn't work. And now I am getting a issue with system.memory. But this is progress. The question is why is it only loading those two locations and why no dll extension.

Switching to building for net472, fix that the Yubico.NativeShims didnt have a dll extention. But I still have the different versions of System.Memory. Looks like I need to figure out how to do bindingRedirect. I am still getting error about 4.0.1.1 missing, that is 4.5.4 and System.Formats.Cbor required 4.5.5.

But this is really helpful. I would love not to need to put the DLL in the protected folders but that might be out of your hands.

Sorry I didnt explain enough. The reason why it took so long for me to get back, is that I learned how to do a compiled powershell module. So I just set the target and then did a dotnet build and process takes the dlls from %HOMEPATH%.nuget\packages\yubico.yubikey\1.7.0 etc..

And since my code is now a compiled DLL i think I need to understand bindingredirects as yubico.yubikey and its dependency:

Yubico.Core: System.Memory >= 4.5.4 System.Formats.Cbor: System.Memory >= 4.5.5

GregDomzalski commented 1 year ago

Oh, I gotcha. Interesting - so your compiled project's target framework is .NET 4.x and you're still getting the System.Memory issues? That should have been resolved a long time ago ~SDK 1.3.0

Yeah, perhaps if you have other dependencies they could be interfering. The BindingRedirects might be your fix there.

As for the DLL path. If you are able to use .NET Core (I'm not sure if system PowerShell will let you as it's .NET 4.x based) you could possibly use this trick: https://stackoverflow.com/questions/69958594/how-to-select-the-path-for-dllimport-at-run-time-when-the-name-of-the-required-d/69958827#69958827. NativeLibrary.Load is available from .NET Core 3 onwards, I believe.

Basically the idea is - if you manage to load a library into the process, Windows shouldn't attempt to reload a module with the same name. So you might be able to "trick" .NET into using different paths.

It's a long shot, but an avenue worth exploring.

virot commented 1 year ago

I spent a long time learning how to build a binary module, with lots of new knowledge. Without even a thought of procmon. but after you reminding me I have a solution without binary module even.. this is where it goes wild :)

Using Powershell 7.3 I can get it to work without putting things in the system32 folder. The Yubico.NativeShims.dll needs to reside in a folder called win-x64 (or I guess what os-arch you have) AND the file have to have end in .dll.dll

Then it works. now I am stuck.. I can do it via script module, but a binary module offers so much in overloading etc.. :)

virot commented 1 year ago

The dlls needed to interact with the DLLs with powershell scripts are on my Windows 10 PC: Microsoft.Bcl.HashCode.dll Microsoft.Extensions.Logging.Abstractions.dll Yubico.Core.dll Yubico.DotNetPolyfills.dll Yubico.YubiKey.dll win-x64\Yubico.NativeShims.dll.dll

GregDomzalski commented 1 year ago

Yeah - one thing to keep in mind is that there's a difference in framework for the system PowerShell (the one that comes with Windows) and PowerShell Core (the one you install on your own).

System PowerShell is based off of .NET Framework 4.x, and so will therefor require all those versions of the SDK assemblies (YubiKey, Core, DotnetPolyfills) in order to work 100% properly.

PowerShell Core on the other hand (7.x), is based off of .NET Core (or 6) and so will better work with the netstandard2.1 assemblies from the SDK.

The implications of this is that certain support libraries like Microsoft.Bcl.HashCode and System.Memory may be present with the one version, but not the other. Or at least the version of those will need to match the overall framework environment you're running in.

I suppose it does make sense that you would need to copy some of our dependencies into your runtime directory as well, so some of what you described above is likely to be expected.

DennisDyallo commented 6 months ago

Hi @virot ! Were you able to find somehting that works for you?

DennisDyallo commented 6 months ago

Closing old issues. Feel free to reopen if this is still important to you.

virot commented 6 months ago

Sorry for late reply, I am learning working with C# to resolve issue with, positive results. Please keep closed.

DennisDyallo commented 6 months ago

Let us know if you find a reliable solution! Thanks @virot