diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs b/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs deleted file mode 100644 index df3ad7b2f3f..00000000000 --- a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs +++ /dev/null @@ -1,706 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -namespace Org.OpenAPITools.Client -{ - /// - /// Class for HttpSigning auth related parameter and methods - /// - public class HttpSigningConfiguration - { - #region - /// - /// Initailize the HashAlgorithm and SigningAlgorithm to default value - /// - public HttpSigningConfiguration() - { - HashAlgorithm = HashAlgorithmName.SHA256; - SigningAlgorithm = "PKCS1-v15"; - } - #endregion - - #region Properties - /// - ///Gets the Api keyId - /// - public string KeyId { get; set; } - - /// - /// Gets the Key file path - /// - public string KeyFilePath { get; set; } - - /// - /// Gets the key pass phrase for password protected key - /// - public SecureString KeyPassPhrase { get; set; } - - /// - /// Gets the HTTP signing header - /// - public List HttpSigningHeader { get; set; } - - /// - /// Gets the hash algorithm sha256 or sha512 - /// - public HashAlgorithmName HashAlgorithm { get; set; } - - /// - /// Gets the signing algorithm - /// - public string SigningAlgorithm { get; set; } - - /// - /// Gets the Signature validaty period in seconds - /// - public int SignatureValidityPeriod { get; set; } - - #endregion - - #region enum - private enum PrivateKeyType - { - None = 0, - RSA = 1, - ECDSA = 2, - } - #endregion - - #region Methods - /// - /// Gets the Headers for HttpSigning - /// - /// - /// - /// - /// - internal Dictionary GetHttpSignedHeader(string basePath,string method, string path, RequestOptions requestOptions) - { - const string HEADER_REQUEST_TARGET = "(request-target)"; - //The time when the HTTP signature expires. The API server should reject HTTP requests - //that have expired. - const string HEADER_EXPIRES = "(expires)"; - //The 'Date' header. - const string HEADER_DATE = "Date"; - //The 'Host' header. - const string HEADER_HOST = "Host"; - //The time when the HTTP signature was generated. - const string HEADER_CREATED = "(created)"; - //When the 'Digest' header is included in the HTTP signature, the client automatically - //computes the digest of the HTTP request body, per RFC 3230. - const string HEADER_DIGEST = "Digest"; - //The 'Authorization' header is automatically generated by the client. It includes - //the list of signed headers and a base64-encoded signature. - const string HEADER_AUTHORIZATION = "Authorization"; - - //Hash table to store singed headers - var HttpSignedRequestHeader = new Dictionary(); - var HttpSignatureHeader = new Dictionary(); - - if (HttpSigningHeader.Count == 0) - { - HttpSigningHeader.Add("(created)"); - } - - if (requestOptions.PathParameters != null) - { - foreach (var pathParam in requestOptions.PathParameters) - { - var tempPath = path.Replace(pathParam.Key, "0"); - path = string.Format(tempPath, pathParam.Value); - } - } - - var httpValues = HttpUtility.ParseQueryString(String.Empty); - foreach (var parameter in requestOptions.QueryParameters) - { - if (parameter.Value.Count > 1) - { // array - foreach (var value in parameter.Value) - { - httpValues.Add(parameter.Key + "[]", value); - } - } - else - { - httpValues.Add(parameter.Key, parameter.Value[0]); - - } - } - var uriBuilder = new UriBuilder(string.Concat(basePath, path)); - uriBuilder.Query = httpValues.ToString(); - - var dateTime = DateTime.Now; - String Digest = String.Empty; - - //get the body - string requestBody = string.Empty; - if (requestOptions.Data != null) - { - var serializerSettings = new JsonSerializerSettings(); - serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - requestBody = JsonConvert.SerializeObject(requestOptions.Data, serializerSettings); - } - - if (HashAlgorithm == HashAlgorithmName.SHA256) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-256={0}", Convert.ToBase64String(bodyDigest)); - } - else if (HashAlgorithm == HashAlgorithmName.SHA512) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-512={0}", Convert.ToBase64String(bodyDigest)); - } - else - { - throw new Exception(string.Format("{0} not supported", HashAlgorithm)); - } - - - foreach (var header in HttpSigningHeader) - { - if (header.Equals(HEADER_REQUEST_TARGET)) - { - var targetUrl = string.Format("{0} {1}{2}", method.ToLower(), uriBuilder.Path, uriBuilder.Query); - HttpSignatureHeader.Add(header.ToLower(), targetUrl); - } - else if (header.Equals(HEADER_EXPIRES)) - { - var expireDateTime = dateTime.AddSeconds(SignatureValidityPeriod); - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(expireDateTime).ToString()); - } - else if (header.Equals(HEADER_DATE)) - { - var utcDateTime = dateTime.ToString("r").ToString(); - HttpSignatureHeader.Add(header.ToLower(), utcDateTime); - HttpSignedRequestHeader.Add(HEADER_DATE, utcDateTime); - } - else if (header.Equals(HEADER_HOST)) - { - HttpSignatureHeader.Add(header.ToLower(), uriBuilder.Host); - HttpSignedRequestHeader.Add(HEADER_HOST, uriBuilder.Host); - } - else if (header.Equals(HEADER_CREATED)) - { - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(dateTime).ToString()); - } - else if (header.Equals(HEADER_DIGEST)) - { - HttpSignedRequestHeader.Add(HEADER_DIGEST, Digest); - HttpSignatureHeader.Add(header.ToLower(), Digest); - } - else - { - bool isHeaderFound = false; - foreach (var item in requestOptions.HeaderParameters) - { - if (string.Equals(item.Key, header, StringComparison.OrdinalIgnoreCase)) - { - HttpSignatureHeader.Add(header.ToLower(), item.Value.ToString()); - isHeaderFound = true; - break; - } - } - if (!isHeaderFound) - { - throw new Exception(string.Format("Cannot sign HTTP request.Request does not contain the {0} header.",header)); - } - } - - } - var headersKeysString = String.Join(" ", HttpSignatureHeader.Keys); - var headerValuesList = new List(); - - foreach (var keyVal in HttpSignatureHeader) - { - headerValuesList.Add(string.Format("{0}: {1}", keyVal.Key, keyVal.Value)); - - } - //Concatinate headers value separated by new line - var headerValuesString = string.Join("\n", headerValuesList); - var signatureStringHash = GetStringHash(HashAlgorithm.ToString(), headerValuesString); - string headerSignatureStr = null; - var keyType = GetKeyType(KeyFilePath); - - if (keyType == PrivateKeyType.RSA) - { - headerSignatureStr = GetRSASignature(signatureStringHash); - } - else if (keyType == PrivateKeyType.ECDSA) - { - headerSignatureStr = GetECDSASignature(signatureStringHash); - } - var cryptographicScheme = "hs2019"; - var authorizationHeaderValue = string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\"", - KeyId, cryptographicScheme); - - - if (HttpSignatureHeader.ContainsKey(HEADER_CREATED)) - { - authorizationHeaderValue += string.Format(",created={0}", HttpSignatureHeader[HEADER_CREATED]); - } - - if (HttpSignatureHeader.ContainsKey(HEADER_EXPIRES)) - { - authorizationHeaderValue += string.Format(",expires={0}", HttpSignatureHeader[HEADER_EXPIRES]); - } - - authorizationHeaderValue += string.Format(",headers=\"{0}\",signature=\"{1}\"", - headersKeysString, headerSignatureStr); - - HttpSignedRequestHeader.Add(HEADER_AUTHORIZATION, authorizationHeaderValue); - - return HttpSignedRequestHeader; - } - - private byte[] GetStringHash(string hashName, string stringToBeHashed) - { - var hashAlgorithm = System.Security.Cryptography.HashAlgorithm.Create(hashName); - - var bytes = Encoding.UTF8.GetBytes(stringToBeHashed); - var stringHash = hashAlgorithm.ComputeHash(bytes); - return stringHash; - } - - private int GetUnixTime(DateTime date2) - { - DateTime date1 = new DateTime(1970, 01, 01); - TimeSpan timeSpan = date2 - date1; - return (int)timeSpan.TotalSeconds; - } - - private string GetRSASignature(byte[] stringToSign) - { - RSA rsa = GetRSAProviderFromPemFile(KeyFilePath, KeyPassPhrase); - if (SigningAlgorithm == "RSASSA-PSS") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pss); - return Convert.ToBase64String(signedbytes); - - } - else if (SigningAlgorithm == "PKCS1-v15") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pkcs1); - return Convert.ToBase64String(signedbytes); - } - return string.Empty; - } - - /// - /// Gets the ECDSA signature - /// - /// - /// - private string GetECDSASignature(byte[] dataToSign) - { - if (!File.Exists(KeyFilePath)) - { - throw new Exception("key file path does not exist."); - } - - var ecKeyHeader = "-----BEGIN EC PRIVATE KEY-----"; - var ecKeyFooter = "-----END EC PRIVATE KEY-----"; - var keyStr = File.ReadAllText(KeyFilePath); - var ecKeyBase64String = keyStr.Replace(ecKeyHeader, "").Replace(ecKeyFooter, "").Trim(); - var keyBytes = System.Convert.FromBase64String(ecKeyBase64String); - var ecdsa = ECDsa.Create(); - var bytCount = 0; - -#if (NETCOREAPP3_0 || NETCOREAPP3_1 || NET5_0) - if (configuration.KeyPassPhrase != null) - { - ecdsa.ImportEncryptedPkcs8PrivateKey(keyPassPhrase, keyBytes, out bytCount); - } - else - { - ecdsa.ImportPkcs8PrivateKey(keyBytes, out bytCount); - } - var signedBytes = ecdsa.SignHash(dataToSign); - var derBytes = ConvertToECDSAANS1Format(signedBytes); - var signedString = System.Convert.ToBase64String(derBytes); - - return signedString; -#else - throw new Exception("ECDSA signing is supported only on NETCOREAPP3_0 and above"); -#endif - - } - - private byte[] ConvertToECDSAANS1Format(byte[] signedBytes) - { - var derBytes = new List(); - byte derLength = 68; //default lenght for ECDSA code signinged bit 0x44 - byte rbytesLength = 32; //R length 0x20 - byte sbytesLength = 32; //S length 0x20 - var rBytes = new List(); - var sBytes = new List(); - for (int i = 0; i < 32; i++) - { - rBytes.Add(signedBytes[i]); - } - for (int i = 32; i < 64; i++) - { - sBytes.Add(signedBytes[i]); - } - - if (rBytes[0] > 0x7F) - { - derLength++; - rbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(rBytes); - rBytes.Clear(); - rBytes.Add(0x00); - rBytes.AddRange(tempBytes); - } - - if (sBytes[0] > 0x7F) - { - derLength++; - sbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(sBytes); - sBytes.Clear(); - sBytes.Add(0x00); - sBytes.AddRange(tempBytes); - - } - - derBytes.Add(48); //start of the sequence 0x30 - derBytes.Add(derLength); //total length r lenth, type and r bytes - - derBytes.Add(2); //tag for integer - derBytes.Add(rbytesLength); //length of r - derBytes.AddRange(rBytes); - - derBytes.Add(2); //tag for integer - derBytes.Add(sbytesLength); //length of s - derBytes.AddRange(sBytes); - return derBytes.ToArray(); - } - - private RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile, SecureString keyPassPharse = null) - { - const String pempubheader = "-----BEGIN PUBLIC KEY-----"; - const String pempubfooter = "-----END PUBLIC KEY-----"; - bool isPrivateKeyFile = true; - byte[] pemkey = null; - - if (!File.Exists(pemfile)) - { - throw new Exception("private key file does not exist."); - } - string pemstr = File.ReadAllText(pemfile).Trim(); - - if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) - { - isPrivateKeyFile = false; - } - - if (isPrivateKeyFile) - { - pemkey = ConvertPrivateKeyToBytes(pemstr, keyPassPharse); - if (pemkey == null) - { - return null; - } - return DecodeRSAPrivateKey(pemkey); - } - return null; - } - - private byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPharse = null) - { - const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----"; - const String pemprivfooter = "-----END RSA PRIVATE KEY-----"; - String pemstr = instr.Trim(); - byte[] binkey; - - if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter)) - { - return null; - } - - StringBuilder sb = new StringBuilder(pemstr); - sb.Replace(pemprivheader, ""); - sb.Replace(pemprivfooter, ""); - String pvkstr = sb.ToString().Trim(); - - try - { // if there are no PEM encryption info lines, this is an UNencrypted PEM private key - binkey = Convert.FromBase64String(pvkstr); - return binkey; - } - catch (System.FormatException) - { - StringReader str = new StringReader(pvkstr); - - //-------- read PEM encryption info. lines and extract salt ----- - if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) - return null; - String saltline = str.ReadLine(); - if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,")) - return null; - String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim(); - byte[] salt = new byte[saltstr.Length / 2]; - for (int i = 0; i < salt.Length; i++) - salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16); - if (!(str.ReadLine() == "")) - return null; - - //------ remaining b64 data is encrypted RSA key ---- - String encryptedstr = str.ReadToEnd(); - - try - { //should have b64 encrypted RSA key now - binkey = Convert.FromBase64String(encryptedstr); - } - catch (System.FormatException) - { //data is not in base64 fromat - return null; - } - - byte[] deskey = GetEncryptedKey(salt, keyPassPharse, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes - if (deskey == null) - return null; - - //------ Decrypt the encrypted 3des-encrypted RSA private key ------ - byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV - return rsakey; - } - } - - private RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) - { - byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; - - // --------- Set up stream to decode the asn.1 encoded RSA private key ------ - MemoryStream mem = new MemoryStream(privkey); - BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading - byte bt = 0; - ushort twobytes = 0; - int elems = 0; - try - { - twobytes = binr.ReadUInt16(); - if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) - binr.ReadByte(); //advance 1 byte - else if (twobytes == 0x8230) - binr.ReadInt16(); //advance 2 bytes - else - return null; - - twobytes = binr.ReadUInt16(); - if (twobytes != 0x0102) //version number - return null; - bt = binr.ReadByte(); - if (bt != 0x00) - return null; - - //------ all private key components are Integer sequences ---- - elems = GetIntegerSize(binr); - MODULUS = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - E = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - D = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - P = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - Q = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DP = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DQ = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - IQ = binr.ReadBytes(elems); - - // ------- create RSACryptoServiceProvider instance and initialize with public key ----- - RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); - RSAParameters RSAparams = new RSAParameters(); - RSAparams.Modulus = MODULUS; - RSAparams.Exponent = E; - RSAparams.D = D; - RSAparams.P = P; - RSAparams.Q = Q; - RSAparams.DP = DP; - RSAparams.DQ = DQ; - RSAparams.InverseQ = IQ; - RSA.ImportParameters(RSAparams); - return RSA; - } - catch (Exception) - { - return null; - } - finally { binr.Close(); } - } - - private int GetIntegerSize(BinaryReader binr) - { - byte bt = 0; - byte lowbyte = 0x00; - byte highbyte = 0x00; - int count = 0; - bt = binr.ReadByte(); - if (bt != 0x02) //expect integer - return 0; - bt = binr.ReadByte(); - - if (bt == 0x81) - count = binr.ReadByte(); // data size in next byte - else if (bt == 0x82) - { - highbyte = binr.ReadByte(); // data size in next 2 bytes - lowbyte = binr.ReadByte(); - byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; - count = BitConverter.ToInt32(modint, 0); - } - else - { - count = bt; // we already have the data size - } - while (binr.ReadByte() == 0x00) - { //remove high order zeros in data - count -= 1; - } - binr.BaseStream.Seek(-1, SeekOrigin.Current); - //last ReadByte wasn't a removed zero, so back up a byte - return count; - } - - private byte[] GetEncryptedKey(byte[] salt, SecureString secpswd, int count, int miter) - { - IntPtr unmanagedPswd = IntPtr.Zero; - int HASHLENGTH = 16; //MD5 bytes - byte[] keymaterial = new byte[HASHLENGTH * miter]; //to store contatenated Mi hashed results - - byte[] psbytes = new byte[secpswd.Length]; - unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); - Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length); - Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); - - // --- contatenate salt and pswd bytes into fixed data array --- - byte[] data00 = new byte[psbytes.Length + salt.Length]; - Array.Copy(psbytes, data00, psbytes.Length); //copy the pswd bytes - Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes - - // ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ---- - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] result = null; - byte[] hashtarget = new byte[HASHLENGTH + data00.Length]; //fixed length initial hashtarget - - for (int j = 0; j < miter; j++) - { - // ---- Now hash consecutively for count times ------ - if (j == 0) - result = data00; //initialize - else - { - Array.Copy(result, hashtarget, result.Length); - Array.Copy(data00, 0, hashtarget, result.Length, data00.Length); - result = hashtarget; - } - - for (int i = 0; i < count; i++) - result = md5.ComputeHash(result); - Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length); //contatenate to keymaterial - } - byte[] deskey = new byte[24]; - Array.Copy(keymaterial, deskey, deskey.Length); - - Array.Clear(psbytes, 0, psbytes.Length); - Array.Clear(data00, 0, data00.Length); - Array.Clear(result, 0, result.Length); - Array.Clear(hashtarget, 0, hashtarget.Length); - Array.Clear(keymaterial, 0, keymaterial.Length); - return deskey; - } - - private byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) - { - MemoryStream memst = new MemoryStream(); - TripleDES alg = TripleDES.Create(); - alg.Key = desKey; - alg.IV = IV; - try - { - CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - } - catch (Exception) - { - return null; - } - byte[] decryptedData = memst.ToArray(); - return decryptedData; - } - - /// - /// Detect the key type from the pem file. - /// - /// key file path in pem format - /// - private PrivateKeyType GetKeyType(string keyFilePath) - { - if (!File.Exists(keyFilePath)) - { - throw new Exception("Key file path does not exist."); - } - - var ecPrivateKeyHeader = "BEGIN EC PRIVATE KEY"; - var ecPrivateKeyFooter = "END EC PRIVATE KEY"; - var rsaPrivateKeyHeader = "BEGIN RSA PRIVATE KEY"; - var rsaPrivateFooter = "END RSA PRIVATE KEY"; - var pkcs8Header = "BEGIN PRIVATE KEY"; - var pkcs8Footer = "END PRIVATE KEY"; - var keyType = PrivateKeyType.None; - var key = File.ReadAllLines(keyFilePath); - - if (key[0].ToString().Contains(rsaPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(rsaPrivateFooter)) - { - keyType = PrivateKeyType.RSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - keyType = PrivateKeyType.ECDSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - - /*this type of key can hold many type different types of private key, but here due lack of pem header - Considering this as EC key - */ - //TODO :- update the key based on oid - keyType = PrivateKeyType.ECDSA; - } - else - { - throw new Exception("Either the key is invalid or key is not supported"); - - } - return keyType; - } - #endregion - } -} diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs b/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs deleted file mode 100644 index 3bf59ad7f45..00000000000 --- a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs +++ /dev/null @@ -1,706 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -namespace Org.OpenAPITools.Client -{ - /// - /// Class for HttpSigning auth related parameter and methods - /// - public class HttpSigningConfiguration - { - #region - /// - /// Initailize the HashAlgorithm and SigningAlgorithm to default value - /// - public HttpSigningConfiguration() - { - HashAlgorithm = HashAlgorithmName.SHA256; - SigningAlgorithm = "PKCS1-v15"; - } - #endregion - - #region Properties - /// - ///Gets the Api keyId - /// - public string KeyId { get; set; } - - /// - /// Gets the Key file path - /// - public string KeyFilePath { get; set; } - - /// - /// Gets the key pass phrase for password protected key - /// - public SecureString KeyPassPhrase { get; set; } - - /// - /// Gets the HTTP signing header - /// - public List HttpSigningHeader { get; set; } - - /// - /// Gets the hash algorithm sha256 or sha512 - /// - public HashAlgorithmName HashAlgorithm { get; set; } - - /// - /// Gets the signing algorithm - /// - public string SigningAlgorithm { get; set; } - - /// - /// Gets the Signature validaty period in seconds - /// - public int SignatureValidityPeriod { get; set; } - - #endregion - - #region enum - private enum PrivateKeyType - { - None = 0, - RSA = 1, - ECDSA = 2, - } - #endregion - - #region Methods - /// - /// Gets the Headers for HttpSigning - /// - /// - /// - /// - /// - internal Dictionary GetHttpSignedHeader(string basePath,string method, string path, RequestOptions requestOptions) - { - const string HEADER_REQUEST_TARGET = "(request-target)"; - //The time when the HTTP signature expires. The API server should reject HTTP requests - //that have expired. - const string HEADER_EXPIRES = "(expires)"; - //The 'Date' header. - const string HEADER_DATE = "Date"; - //The 'Host' header. - const string HEADER_HOST = "Host"; - //The time when the HTTP signature was generated. - const string HEADER_CREATED = "(created)"; - //When the 'Digest' header is included in the HTTP signature, the client automatically - //computes the digest of the HTTP request body, per RFC 3230. - const string HEADER_DIGEST = "Digest"; - //The 'Authorization' header is automatically generated by the client. It includes - //the list of signed headers and a base64-encoded signature. - const string HEADER_AUTHORIZATION = "Authorization"; - - //Hash table to store singed headers - var HttpSignedRequestHeader = new Dictionary(); - var HttpSignatureHeader = new Dictionary(); - - if (HttpSigningHeader.Count == 0) - { - HttpSigningHeader.Add("(created)"); - } - - if (requestOptions.PathParameters != null) - { - foreach (var pathParam in requestOptions.PathParameters) - { - var tempPath = path.Replace(pathParam.Key, "0"); - path = string.Format(tempPath, pathParam.Value); - } - } - - var httpValues = HttpUtility.ParseQueryString(String.Empty); - foreach (var parameter in requestOptions.QueryParameters) - { - if (parameter.Value.Count > 1) - { // array - foreach (var value in parameter.Value) - { - httpValues.Add(parameter.Key + "[]", value); - } - } - else - { - httpValues.Add(parameter.Key, parameter.Value[0]); - - } - } - var uriBuilder = new UriBuilder(string.Concat(basePath, path)); - uriBuilder.Query = httpValues.ToString(); - - var dateTime = DateTime.Now; - String Digest = String.Empty; - - //get the body - string requestBody = string.Empty; - if (requestOptions.Data != null) - { - var serializerSettings = new JsonSerializerSettings(); - serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - requestBody = JsonConvert.SerializeObject(requestOptions.Data, serializerSettings); - } - - if (HashAlgorithm == HashAlgorithmName.SHA256) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-256={0}", Convert.ToBase64String(bodyDigest)); - } - else if (HashAlgorithm == HashAlgorithmName.SHA512) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-512={0}", Convert.ToBase64String(bodyDigest)); - } - else - { - throw new Exception(string.Format("{0} not supported", HashAlgorithm)); - } - - - foreach (var header in HttpSigningHeader) - { - if (header.Equals(HEADER_REQUEST_TARGET)) - { - var targetUrl = string.Format("{0} {1}{2}", method.ToLower(), uriBuilder.Path, uriBuilder.Query); - HttpSignatureHeader.Add(header.ToLower(), targetUrl); - } - else if (header.Equals(HEADER_EXPIRES)) - { - var expireDateTime = dateTime.AddSeconds(SignatureValidityPeriod); - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(expireDateTime).ToString()); - } - else if (header.Equals(HEADER_DATE)) - { - var utcDateTime = dateTime.ToString("r").ToString(); - HttpSignatureHeader.Add(header.ToLower(), utcDateTime); - HttpSignedRequestHeader.Add(HEADER_DATE, utcDateTime); - } - else if (header.Equals(HEADER_HOST)) - { - HttpSignatureHeader.Add(header.ToLower(), uriBuilder.Host); - HttpSignedRequestHeader.Add(HEADER_HOST, uriBuilder.Host); - } - else if (header.Equals(HEADER_CREATED)) - { - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(dateTime).ToString()); - } - else if (header.Equals(HEADER_DIGEST)) - { - HttpSignedRequestHeader.Add(HEADER_DIGEST, Digest); - HttpSignatureHeader.Add(header.ToLower(), Digest); - } - else - { - bool isHeaderFound = false; - foreach (var item in requestOptions.HeaderParameters) - { - if (string.Equals(item.Key, header, StringComparison.OrdinalIgnoreCase)) - { - HttpSignatureHeader.Add(header.ToLower(), item.Value.ToString()); - isHeaderFound = true; - break; - } - } - if (!isHeaderFound) - { - throw new Exception(string.Format("Cannot sign HTTP request.Request does not contain the {0} header.",header)); - } - } - - } - var headersKeysString = String.Join(" ", HttpSignatureHeader.Keys); - var headerValuesList = new List(); - - foreach (var keyVal in HttpSignatureHeader) - { - headerValuesList.Add(string.Format("{0}: {1}", keyVal.Key, keyVal.Value)); - - } - //Concatinate headers value separated by new line - var headerValuesString = string.Join("\n", headerValuesList); - var signatureStringHash = GetStringHash(HashAlgorithm.ToString(), headerValuesString); - string headerSignatureStr = null; - var keyType = GetKeyType(KeyFilePath); - - if (keyType == PrivateKeyType.RSA) - { - headerSignatureStr = GetRSASignature(signatureStringHash); - } - else if (keyType == PrivateKeyType.ECDSA) - { - headerSignatureStr = GetECDSASignature(signatureStringHash); - } - var cryptographicScheme = "hs2019"; - var authorizationHeaderValue = string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\"", - KeyId, cryptographicScheme); - - - if (HttpSignatureHeader.ContainsKey(HEADER_CREATED)) - { - authorizationHeaderValue += string.Format(",created={0}", HttpSignatureHeader[HEADER_CREATED]); - } - - if (HttpSignatureHeader.ContainsKey(HEADER_EXPIRES)) - { - authorizationHeaderValue += string.Format(",expires={0}", HttpSignatureHeader[HEADER_EXPIRES]); - } - - authorizationHeaderValue += string.Format(",headers=\"{0}\",signature=\"{1}\"", - headersKeysString, headerSignatureStr); - - HttpSignedRequestHeader.Add(HEADER_AUTHORIZATION, authorizationHeaderValue); - - return HttpSignedRequestHeader; - } - - private byte[] GetStringHash(string hashName, string stringToBeHashed) - { - var hashAlgorithm = System.Security.Cryptography.HashAlgorithm.Create(hashName); - - var bytes = Encoding.UTF8.GetBytes(stringToBeHashed); - var stringHash = hashAlgorithm.ComputeHash(bytes); - return stringHash; - } - - private int GetUnixTime(DateTime date2) - { - DateTime date1 = new DateTime(1970, 01, 01); - TimeSpan timeSpan = date2 - date1; - return (int)timeSpan.TotalSeconds; - } - - private string GetRSASignature(byte[] stringToSign) - { - RSA rsa = GetRSAProviderFromPemFile(KeyFilePath, KeyPassPhrase); - if (SigningAlgorithm == "RSASSA-PSS") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pss); - return Convert.ToBase64String(signedbytes); - - } - else if (SigningAlgorithm == "PKCS1-v15") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pkcs1); - return Convert.ToBase64String(signedbytes); - } - return string.Empty; - } - - /// - /// Gets the ECDSA signature - /// - /// - /// - private string GetECDSASignature(byte[] dataToSign) - { - if (!File.Exists(KeyFilePath)) - { - throw new Exception("key file path does not exist."); - } - - var ecKeyHeader = "-----BEGIN EC PRIVATE KEY-----"; - var ecKeyFooter = "-----END EC PRIVATE KEY-----"; - var keyStr = File.ReadAllText(KeyFilePath); - var ecKeyBase64String = keyStr.Replace(ecKeyHeader, "").Replace(ecKeyFooter, "").Trim(); - var keyBytes = System.Convert.FromBase64String(ecKeyBase64String); - var ecdsa = ECDsa.Create(); - -#if (NETCOREAPP3_0 || NETCOREAPP3_1 || NET5_0) - var byteCount = 0; - if (configuration.KeyPassPhrase != null) - { - ecdsa.ImportEncryptedPkcs8PrivateKey(keyPassPhrase, keyBytes, out byteCount); - } - else - { - ecdsa.ImportPkcs8PrivateKey(keyBytes, out byteCount); - } - var signedBytes = ecdsa.SignHash(dataToSign); - var derBytes = ConvertToECDSAANS1Format(signedBytes); - var signedString = System.Convert.ToBase64String(derBytes); - - return signedString; -#else - throw new Exception("ECDSA signing is supported only on NETCOREAPP3_0 and above"); -#endif - - } - - private byte[] ConvertToECDSAANS1Format(byte[] signedBytes) - { - var derBytes = new List(); - byte derLength = 68; //default lenght for ECDSA code signinged bit 0x44 - byte rbytesLength = 32; //R length 0x20 - byte sbytesLength = 32; //S length 0x20 - var rBytes = new List(); - var sBytes = new List(); - for (int i = 0; i < 32; i++) - { - rBytes.Add(signedBytes[i]); - } - for (int i = 32; i < 64; i++) - { - sBytes.Add(signedBytes[i]); - } - - if (rBytes[0] > 0x7F) - { - derLength++; - rbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(rBytes); - rBytes.Clear(); - rBytes.Add(0x00); - rBytes.AddRange(tempBytes); - } - - if (sBytes[0] > 0x7F) - { - derLength++; - sbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(sBytes); - sBytes.Clear(); - sBytes.Add(0x00); - sBytes.AddRange(tempBytes); - - } - - derBytes.Add(48); //start of the sequence 0x30 - derBytes.Add(derLength); //total length r lenth, type and r bytes - - derBytes.Add(2); //tag for integer - derBytes.Add(rbytesLength); //length of r - derBytes.AddRange(rBytes); - - derBytes.Add(2); //tag for integer - derBytes.Add(sbytesLength); //length of s - derBytes.AddRange(sBytes); - return derBytes.ToArray(); - } - - private RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile, SecureString keyPassPharse = null) - { - const String pempubheader = "-----BEGIN PUBLIC KEY-----"; - const String pempubfooter = "-----END PUBLIC KEY-----"; - bool isPrivateKeyFile = true; - byte[] pemkey = null; - - if (!File.Exists(pemfile)) - { - throw new Exception("private key file does not exist."); - } - string pemstr = File.ReadAllText(pemfile).Trim(); - - if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) - { - isPrivateKeyFile = false; - } - - if (isPrivateKeyFile) - { - pemkey = ConvertPrivateKeyToBytes(pemstr, keyPassPharse); - if (pemkey == null) - { - return null; - } - return DecodeRSAPrivateKey(pemkey); - } - return null; - } - - private byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPharse = null) - { - const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----"; - const String pemprivfooter = "-----END RSA PRIVATE KEY-----"; - String pemstr = instr.Trim(); - byte[] binkey; - - if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter)) - { - return null; - } - - StringBuilder sb = new StringBuilder(pemstr); - sb.Replace(pemprivheader, ""); - sb.Replace(pemprivfooter, ""); - String pvkstr = sb.ToString().Trim(); - - try - { // if there are no PEM encryption info lines, this is an UNencrypted PEM private key - binkey = Convert.FromBase64String(pvkstr); - return binkey; - } - catch (System.FormatException) - { - StringReader str = new StringReader(pvkstr); - - //-------- read PEM encryption info. lines and extract salt ----- - if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) - return null; - String saltline = str.ReadLine(); - if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,")) - return null; - String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim(); - byte[] salt = new byte[saltstr.Length / 2]; - for (int i = 0; i < salt.Length; i++) - salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16); - if (!(str.ReadLine() == "")) - return null; - - //------ remaining b64 data is encrypted RSA key ---- - String encryptedstr = str.ReadToEnd(); - - try - { //should have b64 encrypted RSA key now - binkey = Convert.FromBase64String(encryptedstr); - } - catch (System.FormatException) - { //data is not in base64 fromat - return null; - } - - byte[] deskey = GetEncryptedKey(salt, keyPassPharse, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes - if (deskey == null) - return null; - - //------ Decrypt the encrypted 3des-encrypted RSA private key ------ - byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV - return rsakey; - } - } - - private RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) - { - byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; - - // --------- Set up stream to decode the asn.1 encoded RSA private key ------ - MemoryStream mem = new MemoryStream(privkey); - BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading - byte bt = 0; - ushort twobytes = 0; - int elems = 0; - try - { - twobytes = binr.ReadUInt16(); - if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) - binr.ReadByte(); //advance 1 byte - else if (twobytes == 0x8230) - binr.ReadInt16(); //advance 2 bytes - else - return null; - - twobytes = binr.ReadUInt16(); - if (twobytes != 0x0102) //version number - return null; - bt = binr.ReadByte(); - if (bt != 0x00) - return null; - - //------ all private key components are Integer sequences ---- - elems = GetIntegerSize(binr); - MODULUS = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - E = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - D = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - P = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - Q = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DP = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DQ = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - IQ = binr.ReadBytes(elems); - - // ------- create RSACryptoServiceProvider instance and initialize with public key ----- - RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); - RSAParameters RSAparams = new RSAParameters(); - RSAparams.Modulus = MODULUS; - RSAparams.Exponent = E; - RSAparams.D = D; - RSAparams.P = P; - RSAparams.Q = Q; - RSAparams.DP = DP; - RSAparams.DQ = DQ; - RSAparams.InverseQ = IQ; - RSA.ImportParameters(RSAparams); - return RSA; - } - catch (Exception) - { - return null; - } - finally { binr.Close(); } - } - - private int GetIntegerSize(BinaryReader binr) - { - byte bt = 0; - byte lowbyte = 0x00; - byte highbyte = 0x00; - int count = 0; - bt = binr.ReadByte(); - if (bt != 0x02) //expect integer - return 0; - bt = binr.ReadByte(); - - if (bt == 0x81) - count = binr.ReadByte(); // data size in next byte - else if (bt == 0x82) - { - highbyte = binr.ReadByte(); // data size in next 2 bytes - lowbyte = binr.ReadByte(); - byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; - count = BitConverter.ToInt32(modint, 0); - } - else - { - count = bt; // we already have the data size - } - while (binr.ReadByte() == 0x00) - { //remove high order zeros in data - count -= 1; - } - binr.BaseStream.Seek(-1, SeekOrigin.Current); - //last ReadByte wasn't a removed zero, so back up a byte - return count; - } - - private byte[] GetEncryptedKey(byte[] salt, SecureString secpswd, int count, int miter) - { - IntPtr unmanagedPswd = IntPtr.Zero; - int HASHLENGTH = 16; //MD5 bytes - byte[] keymaterial = new byte[HASHLENGTH * miter]; //to store contatenated Mi hashed results - - byte[] psbytes = new byte[secpswd.Length]; - unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); - Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length); - Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); - - // --- contatenate salt and pswd bytes into fixed data array --- - byte[] data00 = new byte[psbytes.Length + salt.Length]; - Array.Copy(psbytes, data00, psbytes.Length); //copy the pswd bytes - Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes - - // ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ---- - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] result = null; - byte[] hashtarget = new byte[HASHLENGTH + data00.Length]; //fixed length initial hashtarget - - for (int j = 0; j < miter; j++) - { - // ---- Now hash consecutively for count times ------ - if (j == 0) - result = data00; //initialize - else - { - Array.Copy(result, hashtarget, result.Length); - Array.Copy(data00, 0, hashtarget, result.Length, data00.Length); - result = hashtarget; - } - - for (int i = 0; i < count; i++) - result = md5.ComputeHash(result); - Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length); //contatenate to keymaterial - } - byte[] deskey = new byte[24]; - Array.Copy(keymaterial, deskey, deskey.Length); - - Array.Clear(psbytes, 0, psbytes.Length); - Array.Clear(data00, 0, data00.Length); - Array.Clear(result, 0, result.Length); - Array.Clear(hashtarget, 0, hashtarget.Length); - Array.Clear(keymaterial, 0, keymaterial.Length); - return deskey; - } - - private byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) - { - MemoryStream memst = new MemoryStream(); - TripleDES alg = TripleDES.Create(); - alg.Key = desKey; - alg.IV = IV; - try - { - CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - } - catch (Exception) - { - return null; - } - byte[] decryptedData = memst.ToArray(); - return decryptedData; - } - - /// - /// Detect the key type from the pem file. - /// - /// key file path in pem format - /// - private PrivateKeyType GetKeyType(string keyFilePath) - { - if (!File.Exists(keyFilePath)) - { - throw new Exception("Key file path does not exist."); - } - - var ecPrivateKeyHeader = "BEGIN EC PRIVATE KEY"; - var ecPrivateKeyFooter = "END EC PRIVATE KEY"; - var rsaPrivateKeyHeader = "BEGIN RSA PRIVATE KEY"; - var rsaPrivateFooter = "END RSA PRIVATE KEY"; - //var pkcs8Header = "BEGIN PRIVATE KEY"; - //var pkcs8Footer = "END PRIVATE KEY"; - var keyType = PrivateKeyType.None; - var key = File.ReadAllLines(keyFilePath); - - if (key[0].ToString().Contains(rsaPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(rsaPrivateFooter)) - { - keyType = PrivateKeyType.RSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - keyType = PrivateKeyType.ECDSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - - /*this type of key can hold many type different types of private key, but here due lack of pem header - Considering this as EC key - */ - //TODO :- update the key based on oid - keyType = PrivateKeyType.ECDSA; - } - else - { - throw new Exception("Either the key is invalid or key is not supported"); - - } - return keyType; - } - #endregion - } -} diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs b/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs deleted file mode 100644 index df3ad7b2f3f..00000000000 --- a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HTTPSigningConfiguration.cs +++ /dev/null @@ -1,706 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -namespace Org.OpenAPITools.Client -{ - /// - /// Class for HttpSigning auth related parameter and methods - /// - public class HttpSigningConfiguration - { - #region - /// - /// Initailize the HashAlgorithm and SigningAlgorithm to default value - /// - public HttpSigningConfiguration() - { - HashAlgorithm = HashAlgorithmName.SHA256; - SigningAlgorithm = "PKCS1-v15"; - } - #endregion - - #region Properties - /// - ///Gets the Api keyId - /// - public string KeyId { get; set; } - - /// - /// Gets the Key file path - /// - public string KeyFilePath { get; set; } - - /// - /// Gets the key pass phrase for password protected key - /// - public SecureString KeyPassPhrase { get; set; } - - /// - /// Gets the HTTP signing header - /// - public List HttpSigningHeader { get; set; } - - /// - /// Gets the hash algorithm sha256 or sha512 - /// - public HashAlgorithmName HashAlgorithm { get; set; } - - /// - /// Gets the signing algorithm - /// - public string SigningAlgorithm { get; set; } - - /// - /// Gets the Signature validaty period in seconds - /// - public int SignatureValidityPeriod { get; set; } - - #endregion - - #region enum - private enum PrivateKeyType - { - None = 0, - RSA = 1, - ECDSA = 2, - } - #endregion - - #region Methods - /// - /// Gets the Headers for HttpSigning - /// - /// - /// - /// - /// - internal Dictionary GetHttpSignedHeader(string basePath,string method, string path, RequestOptions requestOptions) - { - const string HEADER_REQUEST_TARGET = "(request-target)"; - //The time when the HTTP signature expires. The API server should reject HTTP requests - //that have expired. - const string HEADER_EXPIRES = "(expires)"; - //The 'Date' header. - const string HEADER_DATE = "Date"; - //The 'Host' header. - const string HEADER_HOST = "Host"; - //The time when the HTTP signature was generated. - const string HEADER_CREATED = "(created)"; - //When the 'Digest' header is included in the HTTP signature, the client automatically - //computes the digest of the HTTP request body, per RFC 3230. - const string HEADER_DIGEST = "Digest"; - //The 'Authorization' header is automatically generated by the client. It includes - //the list of signed headers and a base64-encoded signature. - const string HEADER_AUTHORIZATION = "Authorization"; - - //Hash table to store singed headers - var HttpSignedRequestHeader = new Dictionary(); - var HttpSignatureHeader = new Dictionary(); - - if (HttpSigningHeader.Count == 0) - { - HttpSigningHeader.Add("(created)"); - } - - if (requestOptions.PathParameters != null) - { - foreach (var pathParam in requestOptions.PathParameters) - { - var tempPath = path.Replace(pathParam.Key, "0"); - path = string.Format(tempPath, pathParam.Value); - } - } - - var httpValues = HttpUtility.ParseQueryString(String.Empty); - foreach (var parameter in requestOptions.QueryParameters) - { - if (parameter.Value.Count > 1) - { // array - foreach (var value in parameter.Value) - { - httpValues.Add(parameter.Key + "[]", value); - } - } - else - { - httpValues.Add(parameter.Key, parameter.Value[0]); - - } - } - var uriBuilder = new UriBuilder(string.Concat(basePath, path)); - uriBuilder.Query = httpValues.ToString(); - - var dateTime = DateTime.Now; - String Digest = String.Empty; - - //get the body - string requestBody = string.Empty; - if (requestOptions.Data != null) - { - var serializerSettings = new JsonSerializerSettings(); - serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - requestBody = JsonConvert.SerializeObject(requestOptions.Data, serializerSettings); - } - - if (HashAlgorithm == HashAlgorithmName.SHA256) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-256={0}", Convert.ToBase64String(bodyDigest)); - } - else if (HashAlgorithm == HashAlgorithmName.SHA512) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-512={0}", Convert.ToBase64String(bodyDigest)); - } - else - { - throw new Exception(string.Format("{0} not supported", HashAlgorithm)); - } - - - foreach (var header in HttpSigningHeader) - { - if (header.Equals(HEADER_REQUEST_TARGET)) - { - var targetUrl = string.Format("{0} {1}{2}", method.ToLower(), uriBuilder.Path, uriBuilder.Query); - HttpSignatureHeader.Add(header.ToLower(), targetUrl); - } - else if (header.Equals(HEADER_EXPIRES)) - { - var expireDateTime = dateTime.AddSeconds(SignatureValidityPeriod); - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(expireDateTime).ToString()); - } - else if (header.Equals(HEADER_DATE)) - { - var utcDateTime = dateTime.ToString("r").ToString(); - HttpSignatureHeader.Add(header.ToLower(), utcDateTime); - HttpSignedRequestHeader.Add(HEADER_DATE, utcDateTime); - } - else if (header.Equals(HEADER_HOST)) - { - HttpSignatureHeader.Add(header.ToLower(), uriBuilder.Host); - HttpSignedRequestHeader.Add(HEADER_HOST, uriBuilder.Host); - } - else if (header.Equals(HEADER_CREATED)) - { - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(dateTime).ToString()); - } - else if (header.Equals(HEADER_DIGEST)) - { - HttpSignedRequestHeader.Add(HEADER_DIGEST, Digest); - HttpSignatureHeader.Add(header.ToLower(), Digest); - } - else - { - bool isHeaderFound = false; - foreach (var item in requestOptions.HeaderParameters) - { - if (string.Equals(item.Key, header, StringComparison.OrdinalIgnoreCase)) - { - HttpSignatureHeader.Add(header.ToLower(), item.Value.ToString()); - isHeaderFound = true; - break; - } - } - if (!isHeaderFound) - { - throw new Exception(string.Format("Cannot sign HTTP request.Request does not contain the {0} header.",header)); - } - } - - } - var headersKeysString = String.Join(" ", HttpSignatureHeader.Keys); - var headerValuesList = new List(); - - foreach (var keyVal in HttpSignatureHeader) - { - headerValuesList.Add(string.Format("{0}: {1}", keyVal.Key, keyVal.Value)); - - } - //Concatinate headers value separated by new line - var headerValuesString = string.Join("\n", headerValuesList); - var signatureStringHash = GetStringHash(HashAlgorithm.ToString(), headerValuesString); - string headerSignatureStr = null; - var keyType = GetKeyType(KeyFilePath); - - if (keyType == PrivateKeyType.RSA) - { - headerSignatureStr = GetRSASignature(signatureStringHash); - } - else if (keyType == PrivateKeyType.ECDSA) - { - headerSignatureStr = GetECDSASignature(signatureStringHash); - } - var cryptographicScheme = "hs2019"; - var authorizationHeaderValue = string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\"", - KeyId, cryptographicScheme); - - - if (HttpSignatureHeader.ContainsKey(HEADER_CREATED)) - { - authorizationHeaderValue += string.Format(",created={0}", HttpSignatureHeader[HEADER_CREATED]); - } - - if (HttpSignatureHeader.ContainsKey(HEADER_EXPIRES)) - { - authorizationHeaderValue += string.Format(",expires={0}", HttpSignatureHeader[HEADER_EXPIRES]); - } - - authorizationHeaderValue += string.Format(",headers=\"{0}\",signature=\"{1}\"", - headersKeysString, headerSignatureStr); - - HttpSignedRequestHeader.Add(HEADER_AUTHORIZATION, authorizationHeaderValue); - - return HttpSignedRequestHeader; - } - - private byte[] GetStringHash(string hashName, string stringToBeHashed) - { - var hashAlgorithm = System.Security.Cryptography.HashAlgorithm.Create(hashName); - - var bytes = Encoding.UTF8.GetBytes(stringToBeHashed); - var stringHash = hashAlgorithm.ComputeHash(bytes); - return stringHash; - } - - private int GetUnixTime(DateTime date2) - { - DateTime date1 = new DateTime(1970, 01, 01); - TimeSpan timeSpan = date2 - date1; - return (int)timeSpan.TotalSeconds; - } - - private string GetRSASignature(byte[] stringToSign) - { - RSA rsa = GetRSAProviderFromPemFile(KeyFilePath, KeyPassPhrase); - if (SigningAlgorithm == "RSASSA-PSS") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pss); - return Convert.ToBase64String(signedbytes); - - } - else if (SigningAlgorithm == "PKCS1-v15") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pkcs1); - return Convert.ToBase64String(signedbytes); - } - return string.Empty; - } - - /// - /// Gets the ECDSA signature - /// - /// - /// - private string GetECDSASignature(byte[] dataToSign) - { - if (!File.Exists(KeyFilePath)) - { - throw new Exception("key file path does not exist."); - } - - var ecKeyHeader = "-----BEGIN EC PRIVATE KEY-----"; - var ecKeyFooter = "-----END EC PRIVATE KEY-----"; - var keyStr = File.ReadAllText(KeyFilePath); - var ecKeyBase64String = keyStr.Replace(ecKeyHeader, "").Replace(ecKeyFooter, "").Trim(); - var keyBytes = System.Convert.FromBase64String(ecKeyBase64String); - var ecdsa = ECDsa.Create(); - var bytCount = 0; - -#if (NETCOREAPP3_0 || NETCOREAPP3_1 || NET5_0) - if (configuration.KeyPassPhrase != null) - { - ecdsa.ImportEncryptedPkcs8PrivateKey(keyPassPhrase, keyBytes, out bytCount); - } - else - { - ecdsa.ImportPkcs8PrivateKey(keyBytes, out bytCount); - } - var signedBytes = ecdsa.SignHash(dataToSign); - var derBytes = ConvertToECDSAANS1Format(signedBytes); - var signedString = System.Convert.ToBase64String(derBytes); - - return signedString; -#else - throw new Exception("ECDSA signing is supported only on NETCOREAPP3_0 and above"); -#endif - - } - - private byte[] ConvertToECDSAANS1Format(byte[] signedBytes) - { - var derBytes = new List(); - byte derLength = 68; //default lenght for ECDSA code signinged bit 0x44 - byte rbytesLength = 32; //R length 0x20 - byte sbytesLength = 32; //S length 0x20 - var rBytes = new List(); - var sBytes = new List(); - for (int i = 0; i < 32; i++) - { - rBytes.Add(signedBytes[i]); - } - for (int i = 32; i < 64; i++) - { - sBytes.Add(signedBytes[i]); - } - - if (rBytes[0] > 0x7F) - { - derLength++; - rbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(rBytes); - rBytes.Clear(); - rBytes.Add(0x00); - rBytes.AddRange(tempBytes); - } - - if (sBytes[0] > 0x7F) - { - derLength++; - sbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(sBytes); - sBytes.Clear(); - sBytes.Add(0x00); - sBytes.AddRange(tempBytes); - - } - - derBytes.Add(48); //start of the sequence 0x30 - derBytes.Add(derLength); //total length r lenth, type and r bytes - - derBytes.Add(2); //tag for integer - derBytes.Add(rbytesLength); //length of r - derBytes.AddRange(rBytes); - - derBytes.Add(2); //tag for integer - derBytes.Add(sbytesLength); //length of s - derBytes.AddRange(sBytes); - return derBytes.ToArray(); - } - - private RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile, SecureString keyPassPharse = null) - { - const String pempubheader = "-----BEGIN PUBLIC KEY-----"; - const String pempubfooter = "-----END PUBLIC KEY-----"; - bool isPrivateKeyFile = true; - byte[] pemkey = null; - - if (!File.Exists(pemfile)) - { - throw new Exception("private key file does not exist."); - } - string pemstr = File.ReadAllText(pemfile).Trim(); - - if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) - { - isPrivateKeyFile = false; - } - - if (isPrivateKeyFile) - { - pemkey = ConvertPrivateKeyToBytes(pemstr, keyPassPharse); - if (pemkey == null) - { - return null; - } - return DecodeRSAPrivateKey(pemkey); - } - return null; - } - - private byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPharse = null) - { - const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----"; - const String pemprivfooter = "-----END RSA PRIVATE KEY-----"; - String pemstr = instr.Trim(); - byte[] binkey; - - if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter)) - { - return null; - } - - StringBuilder sb = new StringBuilder(pemstr); - sb.Replace(pemprivheader, ""); - sb.Replace(pemprivfooter, ""); - String pvkstr = sb.ToString().Trim(); - - try - { // if there are no PEM encryption info lines, this is an UNencrypted PEM private key - binkey = Convert.FromBase64String(pvkstr); - return binkey; - } - catch (System.FormatException) - { - StringReader str = new StringReader(pvkstr); - - //-------- read PEM encryption info. lines and extract salt ----- - if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) - return null; - String saltline = str.ReadLine(); - if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,")) - return null; - String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim(); - byte[] salt = new byte[saltstr.Length / 2]; - for (int i = 0; i < salt.Length; i++) - salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16); - if (!(str.ReadLine() == "")) - return null; - - //------ remaining b64 data is encrypted RSA key ---- - String encryptedstr = str.ReadToEnd(); - - try - { //should have b64 encrypted RSA key now - binkey = Convert.FromBase64String(encryptedstr); - } - catch (System.FormatException) - { //data is not in base64 fromat - return null; - } - - byte[] deskey = GetEncryptedKey(salt, keyPassPharse, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes - if (deskey == null) - return null; - - //------ Decrypt the encrypted 3des-encrypted RSA private key ------ - byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV - return rsakey; - } - } - - private RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) - { - byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; - - // --------- Set up stream to decode the asn.1 encoded RSA private key ------ - MemoryStream mem = new MemoryStream(privkey); - BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading - byte bt = 0; - ushort twobytes = 0; - int elems = 0; - try - { - twobytes = binr.ReadUInt16(); - if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) - binr.ReadByte(); //advance 1 byte - else if (twobytes == 0x8230) - binr.ReadInt16(); //advance 2 bytes - else - return null; - - twobytes = binr.ReadUInt16(); - if (twobytes != 0x0102) //version number - return null; - bt = binr.ReadByte(); - if (bt != 0x00) - return null; - - //------ all private key components are Integer sequences ---- - elems = GetIntegerSize(binr); - MODULUS = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - E = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - D = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - P = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - Q = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DP = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DQ = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - IQ = binr.ReadBytes(elems); - - // ------- create RSACryptoServiceProvider instance and initialize with public key ----- - RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); - RSAParameters RSAparams = new RSAParameters(); - RSAparams.Modulus = MODULUS; - RSAparams.Exponent = E; - RSAparams.D = D; - RSAparams.P = P; - RSAparams.Q = Q; - RSAparams.DP = DP; - RSAparams.DQ = DQ; - RSAparams.InverseQ = IQ; - RSA.ImportParameters(RSAparams); - return RSA; - } - catch (Exception) - { - return null; - } - finally { binr.Close(); } - } - - private int GetIntegerSize(BinaryReader binr) - { - byte bt = 0; - byte lowbyte = 0x00; - byte highbyte = 0x00; - int count = 0; - bt = binr.ReadByte(); - if (bt != 0x02) //expect integer - return 0; - bt = binr.ReadByte(); - - if (bt == 0x81) - count = binr.ReadByte(); // data size in next byte - else if (bt == 0x82) - { - highbyte = binr.ReadByte(); // data size in next 2 bytes - lowbyte = binr.ReadByte(); - byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; - count = BitConverter.ToInt32(modint, 0); - } - else - { - count = bt; // we already have the data size - } - while (binr.ReadByte() == 0x00) - { //remove high order zeros in data - count -= 1; - } - binr.BaseStream.Seek(-1, SeekOrigin.Current); - //last ReadByte wasn't a removed zero, so back up a byte - return count; - } - - private byte[] GetEncryptedKey(byte[] salt, SecureString secpswd, int count, int miter) - { - IntPtr unmanagedPswd = IntPtr.Zero; - int HASHLENGTH = 16; //MD5 bytes - byte[] keymaterial = new byte[HASHLENGTH * miter]; //to store contatenated Mi hashed results - - byte[] psbytes = new byte[secpswd.Length]; - unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); - Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length); - Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); - - // --- contatenate salt and pswd bytes into fixed data array --- - byte[] data00 = new byte[psbytes.Length + salt.Length]; - Array.Copy(psbytes, data00, psbytes.Length); //copy the pswd bytes - Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes - - // ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ---- - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] result = null; - byte[] hashtarget = new byte[HASHLENGTH + data00.Length]; //fixed length initial hashtarget - - for (int j = 0; j < miter; j++) - { - // ---- Now hash consecutively for count times ------ - if (j == 0) - result = data00; //initialize - else - { - Array.Copy(result, hashtarget, result.Length); - Array.Copy(data00, 0, hashtarget, result.Length, data00.Length); - result = hashtarget; - } - - for (int i = 0; i < count; i++) - result = md5.ComputeHash(result); - Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length); //contatenate to keymaterial - } - byte[] deskey = new byte[24]; - Array.Copy(keymaterial, deskey, deskey.Length); - - Array.Clear(psbytes, 0, psbytes.Length); - Array.Clear(data00, 0, data00.Length); - Array.Clear(result, 0, result.Length); - Array.Clear(hashtarget, 0, hashtarget.Length); - Array.Clear(keymaterial, 0, keymaterial.Length); - return deskey; - } - - private byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) - { - MemoryStream memst = new MemoryStream(); - TripleDES alg = TripleDES.Create(); - alg.Key = desKey; - alg.IV = IV; - try - { - CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - } - catch (Exception) - { - return null; - } - byte[] decryptedData = memst.ToArray(); - return decryptedData; - } - - /// - /// Detect the key type from the pem file. - /// - /// key file path in pem format - /// - private PrivateKeyType GetKeyType(string keyFilePath) - { - if (!File.Exists(keyFilePath)) - { - throw new Exception("Key file path does not exist."); - } - - var ecPrivateKeyHeader = "BEGIN EC PRIVATE KEY"; - var ecPrivateKeyFooter = "END EC PRIVATE KEY"; - var rsaPrivateKeyHeader = "BEGIN RSA PRIVATE KEY"; - var rsaPrivateFooter = "END RSA PRIVATE KEY"; - var pkcs8Header = "BEGIN PRIVATE KEY"; - var pkcs8Footer = "END PRIVATE KEY"; - var keyType = PrivateKeyType.None; - var key = File.ReadAllLines(keyFilePath); - - if (key[0].ToString().Contains(rsaPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(rsaPrivateFooter)) - { - keyType = PrivateKeyType.RSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - keyType = PrivateKeyType.ECDSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - - /*this type of key can hold many type different types of private key, but here due lack of pem header - Considering this as EC key - */ - //TODO :- update the key based on oid - keyType = PrivateKeyType.ECDSA; - } - else - { - throw new Exception("Either the key is invalid or key is not supported"); - - } - return keyType; - } - #endregion - } -} diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs b/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs deleted file mode 100644 index 3bf59ad7f45..00000000000 --- a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/HttpSigningConfiguration.cs +++ /dev/null @@ -1,706 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.InteropServices; -using System.Security; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -namespace Org.OpenAPITools.Client -{ - /// - /// Class for HttpSigning auth related parameter and methods - /// - public class HttpSigningConfiguration - { - #region - /// - /// Initailize the HashAlgorithm and SigningAlgorithm to default value - /// - public HttpSigningConfiguration() - { - HashAlgorithm = HashAlgorithmName.SHA256; - SigningAlgorithm = "PKCS1-v15"; - } - #endregion - - #region Properties - /// - ///Gets the Api keyId - /// - public string KeyId { get; set; } - - /// - /// Gets the Key file path - /// - public string KeyFilePath { get; set; } - - /// - /// Gets the key pass phrase for password protected key - /// - public SecureString KeyPassPhrase { get; set; } - - /// - /// Gets the HTTP signing header - /// - public List HttpSigningHeader { get; set; } - - /// - /// Gets the hash algorithm sha256 or sha512 - /// - public HashAlgorithmName HashAlgorithm { get; set; } - - /// - /// Gets the signing algorithm - /// - public string SigningAlgorithm { get; set; } - - /// - /// Gets the Signature validaty period in seconds - /// - public int SignatureValidityPeriod { get; set; } - - #endregion - - #region enum - private enum PrivateKeyType - { - None = 0, - RSA = 1, - ECDSA = 2, - } - #endregion - - #region Methods - /// - /// Gets the Headers for HttpSigning - /// - /// - /// - /// - /// - internal Dictionary GetHttpSignedHeader(string basePath,string method, string path, RequestOptions requestOptions) - { - const string HEADER_REQUEST_TARGET = "(request-target)"; - //The time when the HTTP signature expires. The API server should reject HTTP requests - //that have expired. - const string HEADER_EXPIRES = "(expires)"; - //The 'Date' header. - const string HEADER_DATE = "Date"; - //The 'Host' header. - const string HEADER_HOST = "Host"; - //The time when the HTTP signature was generated. - const string HEADER_CREATED = "(created)"; - //When the 'Digest' header is included in the HTTP signature, the client automatically - //computes the digest of the HTTP request body, per RFC 3230. - const string HEADER_DIGEST = "Digest"; - //The 'Authorization' header is automatically generated by the client. It includes - //the list of signed headers and a base64-encoded signature. - const string HEADER_AUTHORIZATION = "Authorization"; - - //Hash table to store singed headers - var HttpSignedRequestHeader = new Dictionary(); - var HttpSignatureHeader = new Dictionary(); - - if (HttpSigningHeader.Count == 0) - { - HttpSigningHeader.Add("(created)"); - } - - if (requestOptions.PathParameters != null) - { - foreach (var pathParam in requestOptions.PathParameters) - { - var tempPath = path.Replace(pathParam.Key, "0"); - path = string.Format(tempPath, pathParam.Value); - } - } - - var httpValues = HttpUtility.ParseQueryString(String.Empty); - foreach (var parameter in requestOptions.QueryParameters) - { - if (parameter.Value.Count > 1) - { // array - foreach (var value in parameter.Value) - { - httpValues.Add(parameter.Key + "[]", value); - } - } - else - { - httpValues.Add(parameter.Key, parameter.Value[0]); - - } - } - var uriBuilder = new UriBuilder(string.Concat(basePath, path)); - uriBuilder.Query = httpValues.ToString(); - - var dateTime = DateTime.Now; - String Digest = String.Empty; - - //get the body - string requestBody = string.Empty; - if (requestOptions.Data != null) - { - var serializerSettings = new JsonSerializerSettings(); - serializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - requestBody = JsonConvert.SerializeObject(requestOptions.Data, serializerSettings); - } - - if (HashAlgorithm == HashAlgorithmName.SHA256) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-256={0}", Convert.ToBase64String(bodyDigest)); - } - else if (HashAlgorithm == HashAlgorithmName.SHA512) - { - var bodyDigest = GetStringHash(HashAlgorithm.ToString(), requestBody); - Digest = string.Format("SHA-512={0}", Convert.ToBase64String(bodyDigest)); - } - else - { - throw new Exception(string.Format("{0} not supported", HashAlgorithm)); - } - - - foreach (var header in HttpSigningHeader) - { - if (header.Equals(HEADER_REQUEST_TARGET)) - { - var targetUrl = string.Format("{0} {1}{2}", method.ToLower(), uriBuilder.Path, uriBuilder.Query); - HttpSignatureHeader.Add(header.ToLower(), targetUrl); - } - else if (header.Equals(HEADER_EXPIRES)) - { - var expireDateTime = dateTime.AddSeconds(SignatureValidityPeriod); - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(expireDateTime).ToString()); - } - else if (header.Equals(HEADER_DATE)) - { - var utcDateTime = dateTime.ToString("r").ToString(); - HttpSignatureHeader.Add(header.ToLower(), utcDateTime); - HttpSignedRequestHeader.Add(HEADER_DATE, utcDateTime); - } - else if (header.Equals(HEADER_HOST)) - { - HttpSignatureHeader.Add(header.ToLower(), uriBuilder.Host); - HttpSignedRequestHeader.Add(HEADER_HOST, uriBuilder.Host); - } - else if (header.Equals(HEADER_CREATED)) - { - HttpSignatureHeader.Add(header.ToLower(), GetUnixTime(dateTime).ToString()); - } - else if (header.Equals(HEADER_DIGEST)) - { - HttpSignedRequestHeader.Add(HEADER_DIGEST, Digest); - HttpSignatureHeader.Add(header.ToLower(), Digest); - } - else - { - bool isHeaderFound = false; - foreach (var item in requestOptions.HeaderParameters) - { - if (string.Equals(item.Key, header, StringComparison.OrdinalIgnoreCase)) - { - HttpSignatureHeader.Add(header.ToLower(), item.Value.ToString()); - isHeaderFound = true; - break; - } - } - if (!isHeaderFound) - { - throw new Exception(string.Format("Cannot sign HTTP request.Request does not contain the {0} header.",header)); - } - } - - } - var headersKeysString = String.Join(" ", HttpSignatureHeader.Keys); - var headerValuesList = new List(); - - foreach (var keyVal in HttpSignatureHeader) - { - headerValuesList.Add(string.Format("{0}: {1}", keyVal.Key, keyVal.Value)); - - } - //Concatinate headers value separated by new line - var headerValuesString = string.Join("\n", headerValuesList); - var signatureStringHash = GetStringHash(HashAlgorithm.ToString(), headerValuesString); - string headerSignatureStr = null; - var keyType = GetKeyType(KeyFilePath); - - if (keyType == PrivateKeyType.RSA) - { - headerSignatureStr = GetRSASignature(signatureStringHash); - } - else if (keyType == PrivateKeyType.ECDSA) - { - headerSignatureStr = GetECDSASignature(signatureStringHash); - } - var cryptographicScheme = "hs2019"; - var authorizationHeaderValue = string.Format("Signature keyId=\"{0}\",algorithm=\"{1}\"", - KeyId, cryptographicScheme); - - - if (HttpSignatureHeader.ContainsKey(HEADER_CREATED)) - { - authorizationHeaderValue += string.Format(",created={0}", HttpSignatureHeader[HEADER_CREATED]); - } - - if (HttpSignatureHeader.ContainsKey(HEADER_EXPIRES)) - { - authorizationHeaderValue += string.Format(",expires={0}", HttpSignatureHeader[HEADER_EXPIRES]); - } - - authorizationHeaderValue += string.Format(",headers=\"{0}\",signature=\"{1}\"", - headersKeysString, headerSignatureStr); - - HttpSignedRequestHeader.Add(HEADER_AUTHORIZATION, authorizationHeaderValue); - - return HttpSignedRequestHeader; - } - - private byte[] GetStringHash(string hashName, string stringToBeHashed) - { - var hashAlgorithm = System.Security.Cryptography.HashAlgorithm.Create(hashName); - - var bytes = Encoding.UTF8.GetBytes(stringToBeHashed); - var stringHash = hashAlgorithm.ComputeHash(bytes); - return stringHash; - } - - private int GetUnixTime(DateTime date2) - { - DateTime date1 = new DateTime(1970, 01, 01); - TimeSpan timeSpan = date2 - date1; - return (int)timeSpan.TotalSeconds; - } - - private string GetRSASignature(byte[] stringToSign) - { - RSA rsa = GetRSAProviderFromPemFile(KeyFilePath, KeyPassPhrase); - if (SigningAlgorithm == "RSASSA-PSS") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pss); - return Convert.ToBase64String(signedbytes); - - } - else if (SigningAlgorithm == "PKCS1-v15") - { - var signedbytes = rsa.SignHash(stringToSign, HashAlgorithm, RSASignaturePadding.Pkcs1); - return Convert.ToBase64String(signedbytes); - } - return string.Empty; - } - - /// - /// Gets the ECDSA signature - /// - /// - /// - private string GetECDSASignature(byte[] dataToSign) - { - if (!File.Exists(KeyFilePath)) - { - throw new Exception("key file path does not exist."); - } - - var ecKeyHeader = "-----BEGIN EC PRIVATE KEY-----"; - var ecKeyFooter = "-----END EC PRIVATE KEY-----"; - var keyStr = File.ReadAllText(KeyFilePath); - var ecKeyBase64String = keyStr.Replace(ecKeyHeader, "").Replace(ecKeyFooter, "").Trim(); - var keyBytes = System.Convert.FromBase64String(ecKeyBase64String); - var ecdsa = ECDsa.Create(); - -#if (NETCOREAPP3_0 || NETCOREAPP3_1 || NET5_0) - var byteCount = 0; - if (configuration.KeyPassPhrase != null) - { - ecdsa.ImportEncryptedPkcs8PrivateKey(keyPassPhrase, keyBytes, out byteCount); - } - else - { - ecdsa.ImportPkcs8PrivateKey(keyBytes, out byteCount); - } - var signedBytes = ecdsa.SignHash(dataToSign); - var derBytes = ConvertToECDSAANS1Format(signedBytes); - var signedString = System.Convert.ToBase64String(derBytes); - - return signedString; -#else - throw new Exception("ECDSA signing is supported only on NETCOREAPP3_0 and above"); -#endif - - } - - private byte[] ConvertToECDSAANS1Format(byte[] signedBytes) - { - var derBytes = new List(); - byte derLength = 68; //default lenght for ECDSA code signinged bit 0x44 - byte rbytesLength = 32; //R length 0x20 - byte sbytesLength = 32; //S length 0x20 - var rBytes = new List(); - var sBytes = new List(); - for (int i = 0; i < 32; i++) - { - rBytes.Add(signedBytes[i]); - } - for (int i = 32; i < 64; i++) - { - sBytes.Add(signedBytes[i]); - } - - if (rBytes[0] > 0x7F) - { - derLength++; - rbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(rBytes); - rBytes.Clear(); - rBytes.Add(0x00); - rBytes.AddRange(tempBytes); - } - - if (sBytes[0] > 0x7F) - { - derLength++; - sbytesLength++; - var tempBytes = new List(); - tempBytes.AddRange(sBytes); - sBytes.Clear(); - sBytes.Add(0x00); - sBytes.AddRange(tempBytes); - - } - - derBytes.Add(48); //start of the sequence 0x30 - derBytes.Add(derLength); //total length r lenth, type and r bytes - - derBytes.Add(2); //tag for integer - derBytes.Add(rbytesLength); //length of r - derBytes.AddRange(rBytes); - - derBytes.Add(2); //tag for integer - derBytes.Add(sbytesLength); //length of s - derBytes.AddRange(sBytes); - return derBytes.ToArray(); - } - - private RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile, SecureString keyPassPharse = null) - { - const String pempubheader = "-----BEGIN PUBLIC KEY-----"; - const String pempubfooter = "-----END PUBLIC KEY-----"; - bool isPrivateKeyFile = true; - byte[] pemkey = null; - - if (!File.Exists(pemfile)) - { - throw new Exception("private key file does not exist."); - } - string pemstr = File.ReadAllText(pemfile).Trim(); - - if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) - { - isPrivateKeyFile = false; - } - - if (isPrivateKeyFile) - { - pemkey = ConvertPrivateKeyToBytes(pemstr, keyPassPharse); - if (pemkey == null) - { - return null; - } - return DecodeRSAPrivateKey(pemkey); - } - return null; - } - - private byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPharse = null) - { - const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----"; - const String pemprivfooter = "-----END RSA PRIVATE KEY-----"; - String pemstr = instr.Trim(); - byte[] binkey; - - if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter)) - { - return null; - } - - StringBuilder sb = new StringBuilder(pemstr); - sb.Replace(pemprivheader, ""); - sb.Replace(pemprivfooter, ""); - String pvkstr = sb.ToString().Trim(); - - try - { // if there are no PEM encryption info lines, this is an UNencrypted PEM private key - binkey = Convert.FromBase64String(pvkstr); - return binkey; - } - catch (System.FormatException) - { - StringReader str = new StringReader(pvkstr); - - //-------- read PEM encryption info. lines and extract salt ----- - if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) - return null; - String saltline = str.ReadLine(); - if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,")) - return null; - String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim(); - byte[] salt = new byte[saltstr.Length / 2]; - for (int i = 0; i < salt.Length; i++) - salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16); - if (!(str.ReadLine() == "")) - return null; - - //------ remaining b64 data is encrypted RSA key ---- - String encryptedstr = str.ReadToEnd(); - - try - { //should have b64 encrypted RSA key now - binkey = Convert.FromBase64String(encryptedstr); - } - catch (System.FormatException) - { //data is not in base64 fromat - return null; - } - - byte[] deskey = GetEncryptedKey(salt, keyPassPharse, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes - if (deskey == null) - return null; - - //------ Decrypt the encrypted 3des-encrypted RSA private key ------ - byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV - return rsakey; - } - } - - private RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) - { - byte[] MODULUS, E, D, P, Q, DP, DQ, IQ; - - // --------- Set up stream to decode the asn.1 encoded RSA private key ------ - MemoryStream mem = new MemoryStream(privkey); - BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading - byte bt = 0; - ushort twobytes = 0; - int elems = 0; - try - { - twobytes = binr.ReadUInt16(); - if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) - binr.ReadByte(); //advance 1 byte - else if (twobytes == 0x8230) - binr.ReadInt16(); //advance 2 bytes - else - return null; - - twobytes = binr.ReadUInt16(); - if (twobytes != 0x0102) //version number - return null; - bt = binr.ReadByte(); - if (bt != 0x00) - return null; - - //------ all private key components are Integer sequences ---- - elems = GetIntegerSize(binr); - MODULUS = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - E = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - D = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - P = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - Q = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DP = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - DQ = binr.ReadBytes(elems); - - elems = GetIntegerSize(binr); - IQ = binr.ReadBytes(elems); - - // ------- create RSACryptoServiceProvider instance and initialize with public key ----- - RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); - RSAParameters RSAparams = new RSAParameters(); - RSAparams.Modulus = MODULUS; - RSAparams.Exponent = E; - RSAparams.D = D; - RSAparams.P = P; - RSAparams.Q = Q; - RSAparams.DP = DP; - RSAparams.DQ = DQ; - RSAparams.InverseQ = IQ; - RSA.ImportParameters(RSAparams); - return RSA; - } - catch (Exception) - { - return null; - } - finally { binr.Close(); } - } - - private int GetIntegerSize(BinaryReader binr) - { - byte bt = 0; - byte lowbyte = 0x00; - byte highbyte = 0x00; - int count = 0; - bt = binr.ReadByte(); - if (bt != 0x02) //expect integer - return 0; - bt = binr.ReadByte(); - - if (bt == 0x81) - count = binr.ReadByte(); // data size in next byte - else if (bt == 0x82) - { - highbyte = binr.ReadByte(); // data size in next 2 bytes - lowbyte = binr.ReadByte(); - byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; - count = BitConverter.ToInt32(modint, 0); - } - else - { - count = bt; // we already have the data size - } - while (binr.ReadByte() == 0x00) - { //remove high order zeros in data - count -= 1; - } - binr.BaseStream.Seek(-1, SeekOrigin.Current); - //last ReadByte wasn't a removed zero, so back up a byte - return count; - } - - private byte[] GetEncryptedKey(byte[] salt, SecureString secpswd, int count, int miter) - { - IntPtr unmanagedPswd = IntPtr.Zero; - int HASHLENGTH = 16; //MD5 bytes - byte[] keymaterial = new byte[HASHLENGTH * miter]; //to store contatenated Mi hashed results - - byte[] psbytes = new byte[secpswd.Length]; - unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); - Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length); - Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); - - // --- contatenate salt and pswd bytes into fixed data array --- - byte[] data00 = new byte[psbytes.Length + salt.Length]; - Array.Copy(psbytes, data00, psbytes.Length); //copy the pswd bytes - Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes - - // ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ---- - MD5 md5 = new MD5CryptoServiceProvider(); - byte[] result = null; - byte[] hashtarget = new byte[HASHLENGTH + data00.Length]; //fixed length initial hashtarget - - for (int j = 0; j < miter; j++) - { - // ---- Now hash consecutively for count times ------ - if (j == 0) - result = data00; //initialize - else - { - Array.Copy(result, hashtarget, result.Length); - Array.Copy(data00, 0, hashtarget, result.Length, data00.Length); - result = hashtarget; - } - - for (int i = 0; i < count; i++) - result = md5.ComputeHash(result); - Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length); //contatenate to keymaterial - } - byte[] deskey = new byte[24]; - Array.Copy(keymaterial, deskey, deskey.Length); - - Array.Clear(psbytes, 0, psbytes.Length); - Array.Clear(data00, 0, data00.Length); - Array.Clear(result, 0, result.Length); - Array.Clear(hashtarget, 0, hashtarget.Length); - Array.Clear(keymaterial, 0, keymaterial.Length); - return deskey; - } - - private byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) - { - MemoryStream memst = new MemoryStream(); - TripleDES alg = TripleDES.Create(); - alg.Key = desKey; - alg.IV = IV; - try - { - CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); - cs.Write(cipherData, 0, cipherData.Length); - cs.Close(); - } - catch (Exception) - { - return null; - } - byte[] decryptedData = memst.ToArray(); - return decryptedData; - } - - /// - /// Detect the key type from the pem file. - /// - /// key file path in pem format - /// - private PrivateKeyType GetKeyType(string keyFilePath) - { - if (!File.Exists(keyFilePath)) - { - throw new Exception("Key file path does not exist."); - } - - var ecPrivateKeyHeader = "BEGIN EC PRIVATE KEY"; - var ecPrivateKeyFooter = "END EC PRIVATE KEY"; - var rsaPrivateKeyHeader = "BEGIN RSA PRIVATE KEY"; - var rsaPrivateFooter = "END RSA PRIVATE KEY"; - //var pkcs8Header = "BEGIN PRIVATE KEY"; - //var pkcs8Footer = "END PRIVATE KEY"; - var keyType = PrivateKeyType.None; - var key = File.ReadAllLines(keyFilePath); - - if (key[0].ToString().Contains(rsaPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(rsaPrivateFooter)) - { - keyType = PrivateKeyType.RSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - keyType = PrivateKeyType.ECDSA; - } - else if (key[0].ToString().Contains(ecPrivateKeyHeader) && - key[key.Length - 1].ToString().Contains(ecPrivateKeyFooter)) - { - - /*this type of key can hold many type different types of private key, but here due lack of pem header - Considering this as EC key - */ - //TODO :- update the key based on oid - keyType = PrivateKeyType.ECDSA; - } - else - { - throw new Exception("Either the key is invalid or key is not supported"); - - } - return keyType; - } - #endregion - } -}