diff --git a/.vs/ApiSecuritySolution/xs/UserPrefs.xml b/.vs/ApiSecuritySolution/xs/UserPrefs.xml
new file mode 100644
index 0000000..b3fbf7b
--- /dev/null
+++ b/.vs/ApiSecuritySolution/xs/UserPrefs.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vs/ApiSecuritySolution/xs/sqlite3/db.lock b/.vs/ApiSecuritySolution/xs/sqlite3/db.lock
new file mode 100644
index 0000000..e69de29
diff --git a/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide
new file mode 100644
index 0000000..d15f853
Binary files /dev/null and b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide differ
diff --git a/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-shm b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-shm
new file mode 100644
index 0000000..e7a9a4e
Binary files /dev/null and b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-shm differ
diff --git a/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-wal b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-wal
new file mode 100644
index 0000000..ce6292b
Binary files /dev/null and b/.vs/ApiSecuritySolution/xs/sqlite3/storage.ide-wal differ
diff --git a/ApiUtilLib/ApiAuthorization.cs b/ApiUtilLib/ApiAuthorization.cs
index 65a7fad..fefe627 100644
--- a/ApiUtilLib/ApiAuthorization.cs
+++ b/ApiUtilLib/ApiAuthorization.cs
@@ -4,6 +4,18 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
+using ApexUtilLib;
+using System.Collections.Generic;
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json;
+using System.Linq;
+using Org.BouncyCastle;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
namespace ApiUtilLib
{
@@ -101,12 +113,11 @@ public static RSACryptoServiceProvider PrivateKeyFromP12(string certificateFileN
{
Logger.LogEnterExit(LoggerBase.Args(certificateFileName, "***password***"));
+
var privateCert = new X509Certificate2(System.IO.File.ReadAllBytes(certificateFileName), password, X509KeyStorageFlags.Exportable);
var OriginalPrivateKey = (RSACryptoServiceProvider)privateCert.PrivateKey;
- // Transfer the private key to overcome the following error...
- // System.Security.Cryptography.CryptographicException "Invalid algorithm specified"
if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix)
{
return OriginalPrivateKey;
@@ -120,6 +131,127 @@ public static RSACryptoServiceProvider PrivateKeyFromP12(string certificateFileN
}
}
+ public static string GetL2SignatureFromPEM(string filename, string message, string passPhrase)
+ {
+ Logger.LogEnterExit(LoggerBase.Args(filename, "***password***"));
+ string result = null;
+ try
+ {
+ using (FileStream fs = File.OpenRead(filename))
+ {
+ AsymmetricCipherKeyPair keyPair;
+ var obj = GetRSAProviderFromPem(File.ReadAllText(filename).Trim(), passPhrase);
+ byte[] bytes = Encoding.UTF8.GetBytes(message);
+
+ using (var reader = File.OpenText(filename))
+ keyPair = (AsymmetricCipherKeyPair)new PemReader(reader, new PasswordFinder(passPhrase)).ReadObject();
+ var decryptEngine = new Pkcs1Encoding(new RsaEngine());
+
+ decryptEngine.Init(false, keyPair.Private);
+ var str = obj.SignData(bytes, CryptoConfig.MapNameToOID("SHA256"));
+
+ result = System.Convert.ToBase64String(str);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ return result;
+ }
+
+ public static RSACryptoServiceProvider ImportPrivateKey(string pem)
+ {
+ PemReader pr = new PemReader(new StringReader(pem));
+ AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
+ RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)KeyPair.Private);
+
+ RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
+ csp.ImportParameters(rsaParams);
+ return csp;
+ }
+
+
+ public static X509Certificate2 LoadCertificateFile(string filename, string passPhrase)
+ {
+ X509Certificate2 x509 = null;
+ try
+ {
+ using (FileStream fs = File.OpenRead(filename))
+ {
+ AsymmetricCipherKeyPair keyPair;
+ var obj = GetRSAProviderFromPem(File.ReadAllText(filename).Trim(), passPhrase);
+ byte[] bytes = Encoding.UTF8.GetBytes("message");
+
+ using (var reader = File.OpenText(filename))
+ keyPair = (AsymmetricCipherKeyPair)new PemReader(reader, new PasswordFinder(passPhrase)).ReadObject();
+ var decryptEngine = new Pkcs1Encoding(new RsaEngine());
+
+ decryptEngine.Init(false, keyPair.Private);
+ var str = obj.SignData(bytes, CryptoConfig.MapNameToOID("SHA256"));
+
+ var base64 = System.Convert.ToBase64String(str);
+
+ var privateCert = new X509Certificate2(base64, passPhrase, X509KeyStorageFlags.Exportable);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ return x509;
+ }
+
+
+ public static RSACryptoServiceProvider GetRSAProviderFromPem(String pemstr, string password)
+ {
+ CspParameters cspParameters = new CspParameters();
+ cspParameters.KeyContainerName = "MyKeyContainer";
+ RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParameters);
+
+ Func MakePublicRCSP = (RSACryptoServiceProvider rcsp, RsaKeyParameters rkp) =>
+ {
+ RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
+ rcsp.ImportParameters(rsaParameters);
+ return rsaKey;
+ };
+
+ Func MakePrivateRCSP = (RSACryptoServiceProvider rcsp, RsaPrivateCrtKeyParameters rkp) =>
+ {
+ RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
+ rcsp.ImportParameters(rsaParameters);
+ return rsaKey;
+ };
+ IPasswordFinder pwd;
+ PemReader reader;
+ reader = new PemReader(new StringReader(pemstr), new PasswordFinder(password));
+ object kp = reader.ReadObject();
+
+ if (kp.GetType().GetProperty("Private") != null)
+ {
+ return MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)(((AsymmetricCipherKeyPair)kp).Private));
+ }
+ else
+ {
+ return MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
+ }
+
+
+ }
+
+
+
+ public static byte[] PEM(string type, byte[] data)
+ {
+ string pem = Encoding.ASCII.GetString(data);
+ string header = String.Format("-----BEGIN {0}-----", type);
+ string footer = String.Format("-----END {0}-----", type);
+ int start = pem.IndexOf(header) + header.Length;
+ int end = pem.IndexOf(footer, start);
+ string base64 = pem.Substring(start, (end - start));
+ return Convert.FromBase64String(base64);
+ }
+
public static RSACryptoServiceProvider PublicKeyFromCer(string certificateFileName)
{
Logger.LogEnterExit(LoggerBase.Args(certificateFileName));
@@ -159,57 +291,69 @@ string authPrefix
, string timestamp
, string version)
{
- Logger.LogEnter(LoggerBase.Args(authPrefix, signatureMethod, appId, siteUri, httpMethod, formList, nonce, timestamp));
-
- authPrefix = authPrefix.ToLower();
-
- // make sure that the url are valid
- if (siteUri.Scheme != "http" && siteUri.Scheme != "https")
+ try
{
- throw new System.NotSupportedException("Support http and https protocol only.");
- }
+ Logger.LogEnter(LoggerBase.Args(authPrefix, signatureMethod, appId, siteUri, httpMethod, formList, nonce, timestamp));
- // make sure that the port no and querystring are remove from url
- var url = string.Format("{0}://{1}{2}", siteUri.Scheme, siteUri.Host, siteUri.AbsolutePath);
- Logger.LogInformation("url:: {0}", url);
+ authPrefix = authPrefix.ToLower();
- // helper calss that handle parameters and form fields
- ApiList paramList = new ApiList();
+ // make sure that the url are valid
+ if (siteUri.Scheme != "http" && siteUri.Scheme != "https")
+ {
+ throw new System.NotSupportedException("Support http and https protocol only.");
+ }
- // process QueryString from url by transfering it to paramList
- if (siteUri.Query.Length > 1)
- {
- var queryString = siteUri.Query.Substring(1); // remove the ? from first character
- Logger.LogInformation("queryString:: {0}", queryString);
+ // make sure that the port no and querystring are remove from url
+ var url = string.Format("{0}://{1}{2}", siteUri.Scheme, siteUri.Host, siteUri.AbsolutePath);
+ Logger.LogInformation("url:: {0}", url);
- var paramArr = queryString.Split('&');
- foreach (string item in paramArr)
- {
- var itemArr = item.Split('=');
- paramList.Add(itemArr[0], System.Net.WebUtility.UrlDecode(itemArr[1]));
- }
+ // helper calss that handle parameters and form fields
+ ApiList paramList = new ApiList();
- Logger.LogInformation("paramList:: {0}", paramList);
- }
+ // process QueryString from url by transfering it to paramList
+ if (siteUri.Query.Length > 1)
+ {
+ var queryString = siteUri.Query.Substring(1); // remove the ? from first character
+ Logger.LogInformation("queryString:: {0}", queryString);
+
+ var paramArr = queryString.Split('&');
+ foreach (string item in paramArr)
+ {
+ string key = null;
+ string val = null;
+ var itemArr = item.Split('=');
+ key = itemArr[0];
+ if(itemArr.Length>1)
+ val = itemArr[1];
+ paramList.Add(key, System.Net.WebUtility.UrlDecode(val));
+ }
+
+ Logger.LogInformation("paramList:: {0}", paramList);
+ }
- // add the form fields to paramList
- if (formList != null && formList.Count > 0)
- {
- paramList.AddRange(formList);
- }
+ // add the form fields to paramList
+ if (formList != null && formList.Count > 0)
+ {
+ paramList.AddRange(formList);
+ }
- paramList.Add(authPrefix + "_timestamp", timestamp);
- paramList.Add(authPrefix + "_nonce", nonce);
- paramList.Add(authPrefix + "_app_id", appId);
- paramList.Add(authPrefix + "_signature_method", signatureMethod.ToString());
- paramList.Add(authPrefix + "_version", version);
+ paramList.Add(authPrefix + "_timestamp", timestamp);
+ paramList.Add(authPrefix + "_nonce", nonce);
+ paramList.Add(authPrefix + "_app_id", appId);
+ paramList.Add(authPrefix + "_signature_method", signatureMethod.ToString());
+ paramList.Add(authPrefix + "_version", version);
- string baseString = httpMethod.ToString() + "&" + url + "&" + paramList.ToString();
+ string baseString = httpMethod.ToString() + "&" + url + "&" + paramList.ToString();
- Logger.LogDebug("BaseString:: {0}", baseString);
+ Logger.LogDebug("BaseString:: {0}", baseString);
- Logger.LogExit(LoggerBase.Args(baseString));
- return baseString;
+ Logger.LogExit(LoggerBase.Args(baseString));
+ return baseString;
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
}
public static long NewTimestamp()
@@ -228,12 +372,12 @@ public static string NewNonce()
{
// Buffer storage.
data = new byte[8];
-
// Fill buffer.
rng.GetBytes(data);
}
Logger.LogEnterExit(LoggerBase.Args(nonce.ToString()));
+
return System.Convert.ToBase64String(data);
}
@@ -283,14 +427,14 @@ string realm
var tokenList = new ApiList();
tokenList.Add("realm", realm);
- tokenList.Add(authPrefix + "_timestamp", timestamp);
- tokenList.Add(authPrefix + "_nonce", nonce);
tokenList.Add(authPrefix + "_app_id", appId);
+ tokenList.Add(authPrefix + "_nonce", nonce);
tokenList.Add(authPrefix + "_signature_method", signatureMethod.ToString());
+ tokenList.Add(authPrefix + "_timestamp", timestamp);
tokenList.Add(authPrefix + "_version", version);
tokenList.Add(authPrefix + "_signature", base64Token);
- string authorizationToken = string.Format("{0} {1}", authPrefix.Substring(0, 1).ToUpperInvariant() + authPrefix.Substring(1), tokenList.ToString(",", false, true));
+ string authorizationToken = string.Format("{0} {1}", authPrefix.Substring(0, 1).ToUpperInvariant() + authPrefix.Substring(1), tokenList.ToString(", ", false, true));
Logger.LogDebug("Token :: {0}", authorizationToken);
@@ -426,5 +570,24 @@ public static void InitiateSSLTrust()
Console.WriteLine("{0}", ex);
}
}
+
+ private class PasswordFinder : IPasswordFinder
+ {
+ private string password;
+
+ public PasswordFinder(string password)
+ {
+ this.password = password;
+ }
+
+
+ public char[] GetPassword()
+ {
+ return password.ToCharArray();
+ }
+ }
+
}
+
+
}
diff --git a/ApiUtilLib/ApiList.cs b/ApiUtilLib/ApiList.cs
index 253f8a4..9b5e86d 100644
--- a/ApiUtilLib/ApiList.cs
+++ b/ApiUtilLib/ApiList.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Collections;
+using ApexUtilLib;
namespace ApiUtilLib
{
@@ -27,13 +29,12 @@ public string ToString(string delimiter = "&", bool sort = true, bool quote = fa
// sort by key, than by value
var sortedList = this.OrderBy(k => k.Key,StringComparer.Ordinal).ThenBy(v => v.Value,StringComparer.Ordinal); //Fixed issue to sort by capital letter.
-
foreach (var item in sortedList)
{
format = "{0}={1}";
if (quote) format = "{0}=\"{1}\"";
- if (item.Value == null && !quote)
+ if (item.Value.IsNullOrEmpty() && !quote)
{
list.Add(string.Format("{0}", item.Key, item.Value));
}
@@ -45,7 +46,7 @@ public string ToString(string delimiter = "&", bool sort = true, bool quote = fa
}
else
{
- foreach (var item in this)
+ foreach (var item in this)
{
list.Add(string.Format(format, item.Key, item.Value));
}
diff --git a/ApiUtilLib/ApiUtilLib.csproj b/ApiUtilLib/ApiUtilLib.csproj
index c0c1f76..c821bfc 100644
--- a/ApiUtilLib/ApiUtilLib.csproj
+++ b/ApiUtilLib/ApiUtilLib.csproj
@@ -29,6 +29,12 @@
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
+
+
+ ..\packages\BouncyCastle.1.8.3\lib\BouncyCastle.Crypto.dll
+
@@ -42,6 +48,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/ApiUtilLib/CommonExtensions.cs b/ApiUtilLib/CommonExtensions.cs
new file mode 100644
index 0000000..d1af409
--- /dev/null
+++ b/ApiUtilLib/CommonExtensions.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Text;
+
+namespace ApexUtilLib
+{
+ public static class CommonExtensions
+ {
+ public static bool IsNullOrEmpty(this string value)
+ {
+ if (value == null)
+ return true;
+
+ if (value == String.Empty)
+ return true;
+
+ return false;
+ }
+
+ public static string Unescape(this string txt)
+ {
+ if (string.IsNullOrEmpty(txt)) { return txt; }
+ StringBuilder retval = new StringBuilder(txt.Length);
+ for (int ix = 0; ix < txt.Length;)
+ {
+ int jx = txt.IndexOf('\n', ix);
+ if (jx < 0 || jx == txt.Length - 1) jx = txt.Length;
+ retval.Append(txt, ix, jx - ix);
+ if (jx >= txt.Length) break;
+ var str = txt[jx + 1];
+ switch (txt[jx + 1])
+ {
+ case 'n': retval.Append('\n'); break; // Line feed
+ case 'r': retval.Append('\r'); break; // Carriage return
+ case 't': retval.Append('\t'); break; // Tab
+ case '\\': retval.Append('\\'); break; // Don't escape
+ default: // Unrecognized, copy as-is
+ retval.Append('\\').Append(txt[jx + 1]); break;
+ }
+ ix = jx + 2;
+ }
+ return retval.ToString();
+ }
+
+ public static string RemoveString(this string value, string[] array)
+ {
+ foreach (var item in array)
+ {
+ value = value.Replace(item, "");
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/ApiUtilLib/packages.config b/ApiUtilLib/packages.config
new file mode 100644
index 0000000..3fe4864
--- /dev/null
+++ b/ApiUtilLib/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ApiUtilLibTest/ApiUtilLibTest.csproj b/ApiUtilLibTest/ApiUtilLibTest.csproj
index 8c0254c..08b53bc 100644
--- a/ApiUtilLibTest/ApiUtilLibTest.csproj
+++ b/ApiUtilLibTest/ApiUtilLibTest.csproj
@@ -1,5 +1,6 @@
+
Debug
AnyCPU
@@ -27,8 +28,12 @@
+
+ ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
+
+
- ..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll
+ ..\packages\NUnit.3.10.1\lib\net45\nunit.framework.dll
@@ -36,6 +41,11 @@
+
+
+
+
+
diff --git a/ApiUtilLibTest/BaseService.cs b/ApiUtilLibTest/BaseService.cs
new file mode 100644
index 0000000..60749a2
--- /dev/null
+++ b/ApiUtilLibTest/BaseService.cs
@@ -0,0 +1,135 @@
+using ApexUtilLib;
+using ApiUtilLib;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace ApexUtilLibTest
+{
+ public class BaseService
+ {
+ internal string testDataPath = @"/Users/nsearch/OneDrive/Projects/GovTech/testData/";
+ internal string testCertPath = @"/Users/nsearch/OneDrive/Projects/GovTech/";
+
+ internal ApiUtilLib.SignatureMethod signatureMethod { get; set; }
+ internal ApiUtilLib.HttpMethod httpMethod { get; set; }
+ internal ApiList apiList { get; set; }
+ internal string timeStamp { get; set; }
+ internal string version { get; set; }
+ internal string nonce { get; set; }
+ internal string authPrefix { get; set; }
+ internal string testId { get; set; }
+ internal string appId { get; set; }
+ internal Uri signatureURL { get; set; }
+ internal string expectedResult { get; set; }
+ internal bool errorTest { get; set; }
+ internal string[] skipTest { get; set; }
+ internal string realm { get; set; }
+ internal Uri invokeUrl { get; set; }
+ internal string secret { get; set; }
+ internal string passphrase { get; set; }
+
+ public BaseService()
+ {
+ }
+
+ internal void SetDetaultParams(TestParam paramFile)
+ {
+ try
+ {
+ signatureMethod = paramFile.apiParam.signatureMethod.ParseSignatureMethod(paramFile.apiParam.secret);
+ httpMethod = paramFile.apiParam.httpMethod.ToEnum();
+ apiList = new ApiList();
+ SetApiList(paramFile.apiParam.formData);
+ SetApiList(paramFile.apiParam.queryString);
+ timeStamp = paramFile.apiParam.timestamp;
+ if (paramFile.apiParam.timestamp.IsNullOrEmpty())
+ timeStamp = Convert.ToInt32(DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), 10).ToString();
+ version = paramFile.apiParam.version ?? "1.0";
+ nonce = paramFile.apiParam.nonce ?? ApiUtilLib.ApiAuthorization.NewNonce();
+ authPrefix = paramFile.apiParam.authPrefix;
+ appId = paramFile.apiParam.appID;
+ testId = paramFile.id;
+ signatureURL = paramFile.apiParam.signatureURL.IsNullOrEmpty() == true ? null : new System.Uri(paramFile.apiParam.signatureURL);
+ expectedResult = CommonExtensions.GetCharp(paramFile.expectedResult);
+ errorTest = paramFile.errorTest;
+ skipTest = paramFile.skipTest;
+ invokeUrl = paramFile.apiParam.invokeURL.IsNullOrEmpty() == true ? null : new System.Uri(paramFile.apiParam.invokeURL);
+ secret = paramFile.apiParam.secret ?? null;
+ realm = paramFile.apiParam.realm ?? null;
+ passphrase = paramFile.apiParam.passphrase;// ?? "passwordp12";
+ }
+ catch (Exception ex)
+ {
+ throw ex;
+ }
+ }
+
+ internal void SetApiList(Dictionary