Sunday, 22 July 2018

Self-signed certificates in .NET with RsaCryptoServiceProvider

This article is written after experiencing how difficult it is today to create self-signed certificates that works with .NET and specificially WCF. If you use the default method in Windows, using the cmdlet New-SelfSignedCertificate in Powershell, chances are high that you will stumble upon this error: System.Security.Cryptography.CryptographicException: Invalid provider type specified. A few years back, creating certificates was way easier using makecert.exe Then Windows required the certificates to have length of minimum 1024. After some years passed, makecert.exe was deprecated. Microsoft now offers .NET developers to create a self signed certificate the cmdlet New-SelfSignedCertificate to use in development and test environments. Actually it turns out that you still must adjust the private part of certificate to use the RSACryptoServiceProvider by using OpenSSL to achieve this and then import to the certificate, sadly Microsoft gives developers tools for self-signed certificate generation that needs to use third-part libraries such as SSLR to work properly with .NET, at least this is the case with WCF.. Here is the Powershell script I ended up with:
 Write-Host "Generating a self signed certificate for client in MSMQ WCF demo"

$clientCertFile = "C:\temp\MSMQWcfDemoClient.pfx" 

$clientCertFileRsaFormatted = "C:\temp\MSMQWcfDemoClient.RSAConverted.pfx"

$cert = New-SelfSignedCertificate -Subject "CN=MSMQWcfDemoClient" -certstorelocation cert:\localmachine\my `
-NotAfter (Get-Date).AddYears(3) -KeyLength 2048 -KeySpec KeyExchange
$pwd = ConvertTo-SecureString -String ‘bongo’ -Force -AsPlainText 
$path = 'cert:\localMachine\my\' + $cert.thumbprint 
Export-PfxCertificate -cert $path -FilePath $clientCertFile -Password $pwd

$clientCertPasswordSec = ConvertTo-SecureString "bongo" -AsPlainText -Force


Write-Host "Generating a self signed certificate for server in MSMQ WCF demo"

$serverCertFile = "C:\temp\MSMQWcfDemoServer.pfx" 

$serverCertFileRsaFormatted =  "C:\temp\MSMQWcfDemoServer.RSAConverted.pfx"

$certServer = New-SelfSignedCertificate -Subject "CN=MSMQWcfDemoserver" -certstorelocation cert:\localmachine\my `
  -NotAfter (Get-Date).AddYears(3) -KeyExportPolicy Exportable -KeyLength 2048  -KeySpec KeyExchange
$pwdServer = ConvertTo-SecureString -String ‘kongo’ -Force -AsPlainText
$pathServer = 'cert:\localMachine\my\' + $certServer.thumbprint 
Export-PfxCertificate -cert $pathServer -FilePath $serverCertFile -Password $pwdServer

$serverCertPasswordSec = ConvertTo-SecureString "kongo" -AsPlainText -Force

$command = @'
cmd.exe /c c:\temp\rsaconvert.bat
'@

Write-Host "Starting bat file to convert from CNG to RSA format.." 

Invoke-Expression -Command:$command 

Write-Host "Importing RSA formatted certificates.."

Import-PfxCertificate -FilePath $clientCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\My -Password $clientCertPasswordSec
Import-PfxCertificate -FilePath $clientCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\root -Password $clientCertPasswordSec



Import-PfxCertificate -FilePath $serverCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\My -Password $serverCertPasswordSec
Import-PfxCertificate -FilePath $serverCertFileRsaFormatted -CertStoreLocation Cert:\LocalMachine\root -Password $serverCertPasswordSec

The powershell script uses a bat file that calls Openssl to convert the pfx certificate to use the RSACryptoServiceProvider. This is how the bat file looks like:
echo Generating RSA format certificates for server using OpenSSL..

c:\openssl\openssl.exe pkcs12 -in "C:\temp\MSMQWcfDemoserver.pfx" -nokeys -out "C:\temp\MSMQWcfDemoserver.cer" -passin "pass:kongo"
c:\openssl\OpenSSL.exe pkcs12 -in "C:\temp\MSMQWcfDemoserver.pfx" -nocerts -out "C:\temp\MSMQWcfDemoserver.pem" -passin "pass:kongo" -passout "pass:kongo"
c:\openssl\OpenSSL.exe rsa -inform PEM -in "C:\temp\MSMQWcfDemoserver.pem" -out "C:\temp\MSMQWcfDemoserver.rsa" -passin "pass:kongo" -passout "pass:kongo"
c:\openssl\openssl.exe pkcs12 -export -in  "C:\temp\MSMQWcfDemoserver.cer" -inkey "C:\temp\MSMQWcfDemoserver.rsa" -out "C:\temp\MSMQWcfDemoserver.RSAConverted.pfx" -passin "pass:kongo" -passout "pass:kongo"


echo Generating RSA format certificates for client using OpenSSL..

c:\openssl\openssl.exe pkcs12 -in "C:\temp\MSMQWcfDemoclient.pfx" -nokeys -out "C:\temp\MSMQWcfDemoclient.cer" -passin "pass:bongo"
c:\openssl\OpenSSL.exe pkcs12 -in "C:\temp\MSMQWcfDemoclient.pfx" -nocerts -out "C:\temp\MSMQWcfDemoclient.pem" -passin "pass:bongo" -passout "pass:bongo"
c:\openssl\OpenSSL.exe rsa -inform PEM -in "C:\temp\MSMQWcfDemoclient.pem" -out "C:\temp\MSMQWcfDemoclient.rsa" -passin "pass:bongo" -passout "pass:bongo"
c:\openssl\openssl.exe pkcs12 -export -in  "C:\temp\MSMQWcfDemoclient.cer" -inkey "C:\temp\MSMQWcfDemoclient.rsa" -out "C:\temp\MSMQWcfDemoclient.RSAConverted.pfx" -passin "pass:bongo" -passout "pass:bongo"


The bat file uses OpenSSL to extract (dismantle) the public part of the certificate into a .cer file (this part could have been done with MMC). The next step is to generate a from our existing pfx file to export to a pem file and then a rsa file with OpenSSL. We then meld the .cer file and .rsa file into a converted .pfx file. This file is with the Powershell script automatically imported into the certificate store Personal (My) of certificate location Local Computer. The Powershell script also Import-PfxCertificate to Trusted Root Certification Authorities. Anyways, my goal was to give you a demo about .NET, WCF and NetMsmqBinding using message security, but I first had to get over this hurdle to be able to have some protection in WCF with certificate and had no idea that Microsoft had given developers so cumbersome tools to generate a self signed certificate to actually work with WCF. Now my MSMQ message queue is filled with encrypted and protection MSMQ messages (containing WCF message to be consumed)! :)
Note: the MSMQ queue was inspected using this Powershell script:

#
# InspectMessageQueueWcfContent.ps1
#


#
# InspectMessageQueue.ps1
#

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null


$queuePath = ".\private$\demoqueue3"

Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""


Run-MainDemoIterateMsmq $queuePath



Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
   
    $doc = New-Object System.Xml.XmlDocument;
    $messageLength = [int] $msg.BodyStream.Length


    $buffer = New-Object byte[] $messageLength

    
    $msg.BodyStream.Read($buffer, 0, $messageLength)

    $envelopeStart = Find-SoapEnvelopeStart($buffer)

    $envelopeStart = $envelopeStart - 0

    $envelopeLength = $($buffer.Length - $envelopeStart)
    #Write-Host $envelopeStart


    $stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)

    $elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
    $elm.ReaderQuotas.MaxStringContentLength = 10000000
    $elm.ReaderQuotas.MaxBytesPerRead = 10000000


    $msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);

    $doc.Load($msg1.GetReaderAtBodyContents());

    $msg.BodyStream.Position = 0;



    return $doc;
}

Function Find-SoapEnvelopeStart([byte[]] $stream)
{
    $i = 0;
    $j = 0;
    $prevByte = $stream[$i];
    $curByte = [byte]$j;
    for ($i = 0; $i -lt $stream.Length; $i++)
    {
        $curByte = $stream[$i];
        if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
            break;
        }
        $prevByte = $curByte;
    }
    return $i - 1;
}


Function Run-MainDemoIterateMsmq([string] $queuePath) {

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){
  $xmlDoc = Get-XmlFromWcfMessage $message 
  Write-Host $xmlDoc.OuterXml
 } 


}





Saturday, 21 July 2018

Reading WCF messages in MSMQ queues in Powershell

The last article looked at displaying MSMQ contents for a MSMQ queue used with NetMsmqBinding using Powershell. The message queues contained characters that were unreadable. That is because the message queue items contains actually ready to consume WCF messages. This article will present a new Powershell script where the MSMQ body contents is finally readable using Powershell and .NET WCF classes in System.ServiceModel. Here is how the contents looks using regular methods to extract the MSMQ Message queue items with garbled contents. This is as noted due to the MSMQ queue items each containing a corresponding WCF message.
Let's fix this up by using System.ServiceModel classes!
[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.ServiceModel") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.IO") | Out-Null


$queuePath = ".\private$\demoqueue4"

Write-Host "Powershell MSMQ queue WCF inspector v0.1. Inspecting queue contents of the queue: $queuePath"
Write-Host ""


Run-MainDemoIterateMsmq $queuePath



Function Get-XmlFromWcfMessage([System.Messaging.Message] $msg) {
   
    $doc = New-Object System.Xml.XmlDocument;
    $messageLength = [int] $msg.BodyStream.Length


    $buffer = New-Object byte[] $messageLength

    
    $msg.BodyStream.Read($buffer, 0, $messageLength)

    $envelopeStart = Find-SoapEnvelopeStart($buffer);

    $envelopeLength = $($buffer.Length - $envelopeStart)
    #Write-Host $envelopeStart


    $stream = New-Object System.IO.MemoryStream($buffer, $envelopeStart, $envelopeLength)

    $elm = New-Object System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
    $elm.ReaderQuotas.MaxStringContentLength = 10000000
    $elm.ReaderQuotas.MaxBytesPerRead = 10000000


    $msg1 = $elm.CreateMessageEncoderFactory().Encoder.ReadMessage($stream, 10000000);

    $doc.Load($msg1.GetReaderAtBodyContents());

    $msg.BodyStream.Position = 0;



    return $doc;
}

Function Find-SoapEnvelopeStart([byte[]] $stream)
{
    $i = 0;
    $j = 0;
    $prevByte = $stream[$i];
    $curByte = [byte]$j;
    for ($i = 0; $i -lt $stream.Length; $i++)
    {
        $curByte = $stream[$i];
        if ($curByte -eq [byte] 0x02 -and $prevByte -eq [byte] 0x56) {
            break;
        }
        $prevByte = $curByte;
    }
    return $i - 1;
}


Function Run-MainDemoIterateMsmq([string] $queuePath) {

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){
  $xmlDoc = Get-XmlFromWcfMessage $message 
  Write-Host $xmlDoc.OuterXml
 } 


}
The soap envelope is found looking after the escape sequence "V" followed with the special ANSI character 0x02 (STX = Start of Text). From this point on, the rest of the WCF Message is our SOAP body! We then get readable output!
Finally, the WCF messages inside the MSMQ queue that is filled up using NetMsmqBinding is readable! In my next article I will present a demo solution of how to use NetMsmqBinding in WCF! Until then, you can clone the solution already from here: git clone git@bitbucket.org:toreaurstad/demonetmsmqwcfgit.git

Reading MSMQ contents with Powershell

This article will present two ways to read a MSMQ (Microsoft Message Queue) using Powershell. First, the queue will be read using the GetString method of System.Text.UTF8Encoding:

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
 
$queuePath = ".\private$\myqueue"

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){

 Write-Host (New-Object System.Text.UTF8Encoding).GetString($message.BodyStream.ToArray())

 Write-Host $msg 
}

As an alternative, it is also possible to use the StreamReader (more ceremony really):

[System.Reflection.Assembly]::LoadWithPartialName("System.Messaging") | Out-Null
 
$queuePath = ".\private$\myqueue"

$queue = New-Object System.Messaging.MessageQueue $queuePath

foreach ($message in $queue.GetAllMessages()){

 Write-Host ([Environment]::NewLine)

 $sr = New-Object System.IO.StreamReader($message.BodyStream)

 $message.Formatter = New-Object System.Messaging.XmlMessageFormatter(@(""));
 
 $msg = "";

 while ($sr.Peek() -ge 0){
  $msg += $sr.ReadLine()
 }

 Write-Host $msg 
}

Actually, I was needing a simple way to look at some messages sent with the NetMsmqBinding in WCF, so making a Powershell script seemed the quickest way! WCF does some strange formatting on the message that is sent through the wire, you can though see that our two alternatives gives also a bit different formatting, the first alternative being the most clean and with shortest syntax.
As the reader can see, the contents of the MSMQ queue that the NetMsmqBinding uses shows unreadable characters. That is because the MSMQ message item are containing actually WCF Messages. QueueExplorer showed me this fact, so next article will present a more lengthy version where the content can be properly decoded using Powershell to the rescue!

Tuesday, 3 July 2018

Basic WCF solution in Monodevelop

Basic WCF Solution in Monodevelop

I created a basic solution with a WCF Servicehost and client in Monodevelop today using MX Linux 17 "Horizon". To check it out, clone the following repository:
git clone https://bitbucket.org/toreaurstad/hellowcfmono
The source code is small and can be seen in a browser here: HelloWcfMono source code
If you have not installed Monodevelop in Linux yet, it is available as package "Monodevelop", "Monodevel" or "Monodevelop-complete", for example in MX-Linux I used:
apt-get install monodevel

The HelloWcf solution consists of three projects. The Service project is a console project, running the ServiceHost through the console. You will want to tweak Monodevelop to use External Console by right clicking and selecting Options=>Run=>General: "Run on external console". I just installed xterm to use the console as it is (apt get install xterm). In case Monodevelop crashes when you open the .sln file, another problem with Monodevelop, you can run the following command to open the .sln file directly in the root folder of the cloned repository.: monodevelop HelloWcf.sln
To run the WCF sample, right click on the Host project and choose Set as Startup project Choose first to Rebuild all (Ctrl+F8) to build the Service, Host and Client projects. Now press F5 to debug the Host project. The terminal window should show up, indicating that the WCF Service is running:



Now, switch over to a new terminal window and navigate to the Client project. Go to the bin folder, then the Debug folder. If you did not build Client, there are no files here, so do this now by right clicking on the Client project in Monodevelop and choose build. Now a file called Client.exe should pop up in your console. To run the client, enter: mono Client.exe Then you provide the Service a string through a call WCF service call with the proxy (Client) and get a reply. This project is really the basic set up of a client to get started coding WCF Servicehost and a proxy supporting BasicHttpBinding in .NET System.ServiceModel (which Mono actually supports). Developers can now use Linux and Monodevelop for example and commit code, while other developers use other platforms. The same .sln file can be openened in Visual Studio in Windows for example, while front-end guys use Apple to do their bit. Monodevelop is truly a possible bridge and will you will save money on license costs and freedom to add a lot of free software to use to build your projects. So what are you waiting for, grab hold of Monodevelop today and Linux and try it out! Nice thing to see that Mono framework supports WCF, much can be developed for .NET in Linux!

Saturday, 19 May 2018

Call a Javascript function from Blazor page

This article will show how a Js function can be called from a Blazor page. First off, create a button like this:
 <button class="btn btn-warning" onclick="@SayHelloToBlazor">Click me!</button>
Then define the .Net method to handle the onclick event.
@using Microsoft.AspNetCore.Blazor.Browser.Interop

 private async void ShowAlert()
 {
    if (RegisteredFunction.Invoke("showAlert", "Hello World!"))
        Console.WriteLine("The Js function showAlert was called!");
 }
The code invokes a registered function with the invoke method and passing in the method name and an argument. Note that you must add the Interop namespace to Blazor in AspNetCore. We then add the Js function, but Blazor will give you a compiler error if you put the Js function in the same file as the Blazor page. Instead, add it in the index.html file under wwwroot folder of your Blazor project (check the wwwroot folder). You can define the Js function in a .js file or right into the index.html file.

    Blazor.registerFunction('showAlert', (msg) => {
        console.log(msg);
        alert(msg);
        return true;

    });

Note that if you refactor the Js method, your reference in the .DotNet code of Blazor will of course go stale, and you must update it. Since we return true (as Blazor wants you to do), we can act upon that in the Blazor code as a callback (check the async modifier of the DotNet method). That is what you need to do to get started with calling Javascript from Blazor page running in DotNetCore 2.1 and later.

Thursday, 10 May 2018

Powershell - Search for big files and output to Excel

Here is a Powershell script that you can run to search for the ten biggest files in your current file directory and display them in Excel. My version of Powershell is 5.1 according to the built in Powershell variable $PSVersionTable.PSVersion, so if you run the script in earlier versions of Powershell, the script must be changed a bit.

Write-Host 'Look for big files in current directory' 

$alternatingOddRowColor = 19
$alternatingEventRowColor = 20

$filename = ''

#$filename = Read-Host 'Directory to output filelist? (c:\temp) default'


if ([string]::IsNullOrEmpty($filename)){
 $filename = "c:\temp\\" 
}

$filename = $filename + 
 ([TimeSpan](Get-Date).ToLongTimeString()).Ticks.ToString() + '_Bigfiles' + '.csv'

Write-Host $filename


gci -r | sort Length -desc |
Select-Object @{Name='Filesize(MB)'; Expression = { [int]$($_.Length /1MB) }}, Name, FullName, LastWriteTime -First 10 | 
Export-Csv $filename -NoTypeInformation -Encoding ASCII -UseCulture

$excelFileName = $filename.Replace('.csv', '.xlsx')


$excel = New-Object -ComObject Excel.Application 
$excel.Visible = $true
$excel.Workbooks.Open($filename)

$excel.DisplayAlerts = false

$objWorksheet = $excel.Workbooks.Item(1)

$activeRange = $excel.ActiveWorkbook.ActiveSheet.UsedRange

$activeRange.EntireColumn.AutoFit()

For ($i = 1; $i -le $activeRange.Rows.Count; $i++) { 
 $themeColorIndex = $(If ($($i %2) -eq 0) { $alternatingOddRowColor } 
   Else { $alternatingEventRowColor });

 $currentRow = $excel.ActiveWorkbook.ActiveSheet.UsedRange.Rows($i).EntireRow
 $currentRow.Font.Name = 'Comic Sans MS'
 $currentRow.Interior.ColorIndex =  $themeColorIndex;
 if ($i -eq 1){
  $currentRow.Font.Bold = true 
  $currentRow.Font.Size = 14
 } 
}


$excel.SaveAs($excelFileName,51)

#$excel.Quit()



A timestamp can be created in Powershell using the Get-Date cmdlet, converting the Get-Date DateTime object to a string with ToLongTimeString(), then casting that string into a timestamp and performing a ToString. Like this:

 ([TimeSpan](Get-Date).ToLongTimeString()).Ticks.ToString()

It is nice to have a file size in megabyte with Get-ChildItem That can be achieved using a calculated property in Powershell. This is done with the following construct ${ .. }
@{ Name : 'PropertyName', Expression { $( ..calculation here .. ) }}

#Like this! 

gci -r | sort Length -desc |
Select-Object  @{Name='Filesize(MB)'; Expression = { [int]$($_.Length /1MB) }} , Name, FullName, LastWriteTime -First 10 | 
Export-Csv $filename -NoTypeInformation -Encoding ASCII -UseCulture

After running the Powershell script I could find out why my source code repository seemingly had grown so much in size. The repo was not increased, but the folder Test Results contained almost a gigabyte of disk space after running some web tests and load tests. My .hgignore file ignore these files anyways. The picture below shows how the generated file looks. Of course with a Comic Sans MS. Font