Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
# Conflicts: Resolved conflict in readme file only
#	README.md
  • Loading branch information
angusmillar committed Jun 4, 2021
2 parents a10219a + d6b2e22 commit 1df51d0
Show file tree
Hide file tree
Showing 63 changed files with 1,038 additions and 379 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@

## [SmartHealthCard.Token](https://www.nuget.org/packages/SmartHealthCard.Token/0.1.0-alpha.1): Encode, Decode & Verifiy SMART Health Card JWS tokens
```
Install-Package SmartHealthCard.QRCode -Version 0.1.0-alpha.2
Install-Package SmartHealthCard.QRCode -Version 0.1.0-alpha.3
```


## [SmartHealthCard.QRCode](https://www.nuget.org/packages/SmartHealthCard.QRCode/0.1.0-alpha.1): Encode SMART Health Card JWS token QR Code images
```
Install-Package SmartHealthCard.QRCode -Version 0.1.0-alpha.2
Install-Package SmartHealthCard.QRCode -Version 0.1.0-alpha.1
```

 
Expand Down
93 changes: 93 additions & 0 deletions ReadMeOpenSSLCreateECCkeys.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Taken from : https://www.scottbrady91.com/OpenSSL/Creating-Elliptical-Curve-Keys-using-OpenSSL

Recently, I have been using OpenSSL to generate private keys and X509 certificates
for Elliptical Curve Cryptography (ECC) and then using them in ASP.NET Core for token signing.

In this article, I�m going to show you how to use OpenSSL to generate private and public
keys on the curve of your choice. Check out my other article for how to do the same for RSA
keys.

OpenSSL ECDSA Cheat Sheet
-------------------------------------------------------------------
# find your curve
openssl ecparam -list_curves

# generate a private key for a curve
openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem

# generate corresponding public key
openssl ec -in private-key.pem -pubout -out public-key.pem

# optional: create a self-signed certificate
openssl req -new -x509 -key private-key.pem -out cert.pem -days 360

# optional: convert pem to pfx
openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out cert.pfx
Generating an Elliptical Curve Private Key Using OpenSSL
To start, you will need to choose the curve you will be working with. You can use the
following command to see a list of
supported curve names and descriptions.

openssl ecparam -list_curves
In this example, I am using prime256v1 (secp256r1), which is suitable for JWT signing;
this is the curve used for JOSE�s ES256.
-------------------------------------------------------------------

You can now generate a private key:

openssl ecparam -name prime256v1 -genkey -noout -out private-key.pem
This should give you a PEM file containing your EC private key, which looks something
like the following:

-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIKEubpBiHkZQYlORbCy8gGTz8tzrWsjBJA6GfFCrQ98coAoGCCqGSM49
AwEHoUQDQgAEOr6rMmRRNKuZuwws/hWwFTM6ECEEaJGGARCJUO4UfoURl8b4JThG
t8VDFKeR2i+ZxE+xh/wTBaJ/zvtSqZiNnQ==
-----END EC PRIVATE KEY-----

Creating an EC Public Key from a Private Key Using OpenSSL
Now that you have your private key, you can use it to generate another PEM, containing
only your public key.

openssl ec -in private-key.pem -pubout -out public-key.pem
This should give you another PEM file, containing the public key:

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOr6rMmRRNKuZuwws/hWwFTM6ECEE
aJGGARCJUO4UfoURl8b4JThGt8VDFKeR2i+ZxE+xh/wTBaJ/zvtSqZiNnQ==
-----END PUBLIC KEY-----

Creating an EC Self-Signed Certificate Using OpenSSL
Now that you have a private key, you could use it to generate a self-signed certificate.
This is not required, but it allows you to use the key
for server/client authentication, or gain X509 specific functionality in technologies
such as JWT and SAML.

openssl req -new -x509 -key private-key.pem -out cert.pem -days 360
This will again generate another PEM file, this time containing the certificate created
by your private key:

-----BEGIN CERTIFICATE-----
MIIB4DCCAYWgAwIBAgIUH53ssiPt4JEGx+VJyntCpHL+TdAwCgYIKoZIzj0EAwIw
RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA3MTgxMTE4NDNaFw0yMTA3MTMx
MTE4NDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD
VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO
PQMBBwNCAAQ6vqsyZFE0q5m7DCz+FbAVMzoQIQRokYYBEIlQ7hR+hRGXxvglOEa3
xUMUp5HaL5nET7GH/BMFon/O+1KpmI2do1MwUTAdBgNVHQ4EFgQU9yjFBqAZOMv+
cD6a3KHTWuYrcFEwHwYDVR0jBBgwFoAU9yjFBqAZOMv+cD6a3KHTWuYrcFEwDwYD
VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEAwCpA5Nx083qqUqU6LUd0
vzZLK4etuInxNvXohXH5LiACIQDSI63J4DiN3dq2sPPLw5iQi9MMefcV1iAySbKT
B9BaAw==
-----END CERTIFICATE-----

You could leave things there, but if you are working on Windows, you may prefer a PFX
file that contains both the certificate and the private key for you to export and use.

You can do this using OpenSSL�s pkcs12 command:

openssl pkcs12 -export -inkey private-key.pem -in cert.pem -out cert.pfx
OpenSSL will ask you to create a password for the PFX file. Feel free to leave this blank.

This should leave you with a certificate that Windows can both install and export the
EC private key from.
2 changes: 1 addition & 1 deletion NugetPublishReadme.txt → ReadmeNugetPublish.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
How to pubish to Nuget:
How to publish to Nuget:

1. Rev the version in the project package dialog and save
2. Right click the project and select Pack
Expand Down
21 changes: 16 additions & 5 deletions SmartHealthCard.DecoderDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using SmartHealthCard.Token;
using SmartHealthCard.Token.Certificates;
using SmartHealthCard.Token.Exceptions;
using SmartHealthCard.Token.Model.Jwks;
using SmartHealthCard.Token.Model.Shc;
using SmartHealthCard.Token.Providers;
using SmartHealthCard.Token.Support;
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;

namespace SHC.DecoderDemo
Expand Down Expand Up @@ -61,10 +65,15 @@ static async Task DecoderDemoRunner()
//Or decode and verify, returning the Smart Health Card as a JSON string, throws exceptions if not valid
//string DecodedSmartHealthCardJson = await Decoder.DecodeToJsonAsync(SmartHealthCardJwsToken, Verify: true);
}
catch (Exception Exec)
catch (SmartHealthCardDecoderException DecoderException)
{
Console.WriteLine("The SMART Health Card JWS token was invalid, please see message below:");
Console.WriteLine(Exec.Message);
Console.WriteLine(DecoderException.Message);
}
catch (Exception Exception)
{
Console.WriteLine("Oops, there is an unexpected development exception");
Console.WriteLine(Exception.Message);
}
}
}
Expand All @@ -78,7 +87,7 @@ public MyJwksProvider(X509Certificate2 Certificate)
this.Certificate = Certificate;
}

public Task<JsonWebKeySet> GetJwksAsync(Uri WellKnownJwksUri)
public Task<Result<JsonWebKeySet>> GetJwksAsync(Uri WellKnownJwksUri, CancellationToken? CancellationToken = null)
{
//In production the default implementation of this IJwksProvider interface would
//retrieve the JWKS file from the provided 'WellKnownJwksUri' URL that is found in
Expand All @@ -87,8 +96,10 @@ public Task<JsonWebKeySet> GetJwksAsync(Uri WellKnownJwksUri)
//own JWKS which we have generated from our certificate as seen below.
//This allows you to test before you have a publicly exposed endpoint for you JWKS.
SmartHealthCardJwks SmartHealthCardJwks = new SmartHealthCardJwks();
SmartHealthCard.Token.Model.Jwks.JsonWebKeySet Jwks = SmartHealthCardJwks.GetJsonWebKeySet(new List<X509Certificate2>() { Certificate });
return Task.FromResult(Jwks);
JsonWebKeySet Jwks = SmartHealthCardJwks.GetJsonWebKeySet(new List<X509Certificate2>() { Certificate });
return Task.FromResult(Result<JsonWebKeySet>.Ok(Jwks));
}


}
}
19 changes: 17 additions & 2 deletions SmartHealthCard.EncoderDemo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using SmartHealthCard.QRCode;
using SmartHealthCard.Token;
using SmartHealthCard.Token.Certificates;
using SmartHealthCard.Token.Exceptions;
using SmartHealthCard.Token.Model.Shc;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -58,8 +59,22 @@ static async Task EncoderDemoRunner()
//Instantiate the Smart Health Card Encoder
SmartHealthCardEncoder SmartHealthCardEncoder = new SmartHealthCardEncoder();

//Get the Smart Health Card JWS Token
string SmartHealthCardJwsToken = await SmartHealthCardEncoder.GetTokenAsync(Certificate, SmartHealthCard);
string SmartHealthCardJwsToken = string.Empty;
try
{
//Get the Smart Health Card JWS Token
SmartHealthCardJwsToken = await SmartHealthCardEncoder.GetTokenAsync(Certificate, SmartHealthCard);
}
catch (SmartHealthCardEncoderException EncoderException)
{
Console.WriteLine("The SMART Health Card Encoder has found an error, please see message below:");
Console.WriteLine(EncoderException.Message);
}
catch (Exception Exception)
{
Console.WriteLine("Oops, there is an unexpected development exception");
Console.WriteLine(Exception.Message);
}

//Instantiate the Smart Health Card QR Code Factory
SmartHealthCardQRCodeEncoder SmartHealthCardQRCodeEncoder = new SmartHealthCardQRCodeEncoder();
Expand Down
2 changes: 1 addition & 1 deletion SmartHealthCard.QRCode/SmartHealthCard.QRCode.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
Expand Down
7 changes: 2 additions & 5 deletions SmartHealthCard.QRCode/SmartHealthCardQRCodeDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,9 @@ public SmartHealthCardQRCodeDecoder(
/// <param name="QRCodeRawDataList"></param>
/// <returns></returns>
public string GetToken(List<string> QRCodeRawDataList)
{
IQRCodeDecoder QRCodeDecoder = new QRCodeDecoder();
{
IEnumerable<Chunk> ChunkList = QRCodeDecoder.GetQRCodeChunkList(QRCodeRawDataList);
INumericalModeDecoder NumericalModeDecoder = new NumericalModeDecoder();
string test = NumericalModeDecoder.Decode(ChunkList);
return test;
return NumericalModeDecoder.Decode(ChunkList);
}
}
}
36 changes: 31 additions & 5 deletions SmartHealthCard.Test/Model/FhirDataSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ namespace SmartHealthCard.Test.Model
{
static class FhirDataSupport
{
public static Bundle GetCovid19FhirBundleExample1()
public static Bundle GetCovid19DetectedFhirBundleExample()
{
Patient PatientResource = GetPatientResource("TestFamilyName", "TestGivenName", new DateTime(1973, 09, 30), "61481059995");
Patient PatientResource = GetPatientResource("Coyote", "Wile E", new DateTime(1973, 09, 30), "61481059995");

Coding Code = new Coding(system: "http://loinc.org", code: "94558-4"); //SARS-CoV-2 (COVID-19) Ag [Presence] in Respiratory specimen by Rapid immunoassay
Coding Value = new Coding(system: "http://snomed.info/sct", code: "260373001"); //Detected
Observation CovidResultObservationResource = GetObservationResource(
Expand All @@ -36,6 +36,32 @@ public static Bundle GetCovid19FhirBundleExample1()
return Bundle;
}

public static Bundle GetCovid19NotDetectedFhirBundleExample()
{
Patient PatientResource = GetPatientResource("Coyote", "Wile E", new DateTime(1973, 09, 30), "61481059995");

Coding Code = new Coding(system: "http://loinc.org", code: "94558-4"); //SARS-CoV-2 (COVID-19) Ag [Presence] in Respiratory specimen by Rapid immunoassay
Coding Value = new Coding(system: "http://snomed.info/sct", code: "260415000"); //Not Detected
Observation CovidResultObservationResource = GetObservationResource(
ObsCode: Code,
ObsValue: Value,
EffectiveDate: new DateTime(2021, 05, 24),
PerformerOrganisationName: "ACME Healthcare",
IdentityAssuranceLevelCode: "IAL1.4");

List<Resource> BundleResourceList = new List<Resource>()
{
PatientResource,
CovidResultObservationResource
};

Bundle Bundle = new Bundle();
Bundle.Type = Bundle.BundleType.Collection;
Bundle.Entry = GetBundleResourceEntryList(BundleResourceList);

return Bundle;
}

private static Patient GetPatientResource(string FamilyName, string GivenName, DateTime DateOfBirth, string PhoneNumber)
{
Patient Patient = new Patient();
Expand Down Expand Up @@ -77,7 +103,7 @@ private static Observation GetObservationResource(Coding ObsCode, Coding ObsValu
{
Coding = new List<Coding>()
{
new Coding(system: "http://loinc.org", code: "94558-4")
ObsCode
}
};

Expand All @@ -86,7 +112,7 @@ private static Observation GetObservationResource(Coding ObsCode, Coding ObsValu
{
Coding = new List<Coding>()
{
new Coding(system: "http://snomed.info/sct", code: "260373001")
ObsValue
}
};
Observation.Performer = new List<ResourceReference>()
Expand Down
30 changes: 30 additions & 0 deletions SmartHealthCard.Test/ResourceData.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions SmartHealthCard.Test/ResourceData.resx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,16 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="InvalidJwks" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\InvalidJwks.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="SmartHealthCardCovidExample" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\SmartHealthCardCovidExample.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="TestECC256Cert" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\TestECC256Cert.pem;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="TestECC256Private_key" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\TestECC256Private-key.pem;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
12 changes: 12 additions & 0 deletions SmartHealthCard.Test/Resources/InvalidJwks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"keys": [
{
"kty": "EC",
"kid": "__q7Q4cf6G69ExQSrfW5A_2c3mJrtrRPBhtoRTyZlQM",
"use": "sig",
"alg": "ES256",
"crv": "P-256",
"y": "OPR0AnWPAmhFC6y1RAXFvsAGS0ptfUwuoTKkWXpP4bE"
}
]
}
17 changes: 17 additions & 0 deletions SmartHealthCard.Test/Resources/TestECC256Cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICnTCCAkOgAwIBAgIUVNNmHJZG+2m2bE2NjuYXs5UholswCgYIKoZIzj0EAwIw
gaMxCzAJBgNVBAYTAkFVMQwwCgYDVQQIDANRTEQxETAPBgNVBAcMCEJyaXNiYW5l
MRcwFQYDVQQKDA5Tb25pY0hlYWxoY2FyZTEQMA4GA1UECwwHU29uaWNJVDEUMBIG
A1UEAwwLQW5ndXNNSWxsYXIxMjAwBgkqhkiG9w0BCQEWI2FuZ3VzLm1pbGxhckBz
b25pY2hlYWx0aGNhcmUuY29tLmF1MB4XDTIxMDUxMDA0NTg0MFoXDTIyMDUwNTA0
NTg0MFowgaMxCzAJBgNVBAYTAkFVMQwwCgYDVQQIDANRTEQxETAPBgNVBAcMCEJy
aXNiYW5lMRcwFQYDVQQKDA5Tb25pY0hlYWxoY2FyZTEQMA4GA1UECwwHU29uaWNJ
VDEUMBIGA1UEAwwLQW5ndXNNSWxsYXIxMjAwBgkqhkiG9w0BCQEWI2FuZ3VzLm1p
bGxhckBzb25pY2hlYWx0aGNhcmUuY29tLmF1MFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEj2oyU1JyNT1x66i+PFsdsU1qL+y/Nxq7RjwKkd5kNyc49HQCdY8CaEUL
rLVEBcW+wAZLSm19TC6hMqRZek/hsaNTMFEwHQYDVR0OBBYEFFGC+JzgmozVIEv8
59nMkGR/LIFYMB8GA1UdIwQYMBaAFFGC+JzgmozVIEv859nMkGR/LIFYMA8GA1Ud
EwEB/wQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIhAKwGX0gIrQ1MmKKhf4cKUAI7
PpSgKU3S+wiaNWuQ5aeRAiAF2lYQ+O2TEMVjT5+rm8gQEcmO2FEAvLs3N4hs1Guf
JQ==
-----END CERTIFICATE-----
5 changes: 5 additions & 0 deletions SmartHealthCard.Test/Resources/TestECC256Private-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIHrua8isWUVjVBzQBt+s2QUzyGnh2uO20Siq+ha0pTZaoAoGCCqGSM49
AwEHoUQDQgAEj2oyU1JyNT1x66i+PFsdsU1qL+y/Nxq7RjwKkd5kNyc49HQCdY8C
aEULrLVEBcW+wAZLSm19TC6hMqRZek/hsQ==
-----END EC PRIVATE KEY-----
Loading

0 comments on commit 1df51d0

Please sign in to comment.