We had a C# application connecting to SAP backend systemes using the SAPSSO technology. There has now been a need to replace this with X.509 certificates.
When using SAPSSO, the orginal code would make an HTTP call to the target system, and get a cookie containing the ticket to use:
response = (HttpWebResponse)request.GetResponse();
ticket = response.Cookies["MYSAPSSO2"].Value;
That ticket would then be passed to the RfcCustomDestination object to facilitate a secure connection:
prms.Add(RfcConfigParameters.SAPSSO2Ticket, ticket);
The problem is, I can change the enumerated value from SAPSSO2Ticket to X509Certificate,
prms.Add(RfcConfigParameters.X509Certificate, ticket);
but when I do this, no ticket can be returned from the response, since a MYSAPSSO2 cookie is no longer provided.
So how can I generate the needed ticket value for an X509 certificate?
Related
I'm exhausted after looking for an answer for 3 days. I don't know if my suggested flow is wrong or my Google skills have really deteriorated.
My API needs to create a valid certificate from a CSR it received, by signing it with a private key that exists ONLY inside an HSM-like service (Azure KeyVault), which unfortunately doesn't offer Certificate Authority functions BUT does offer signing data with a key that exists there. My CA certificate's private key is stored in the HSM. I'm using ECDSA.
My suggested flow:
Client generates Key Pair + CSR and sends CSR to API
API creates a certificate from the CSR
API asks HSM to sign the CSR data and receives back a signature
API appends the signature to the certificate and returns a signed (and including CA in chain) certificate to the Client
I'm using C# .NET Core and would like to keep it cross-platform (as it runs in Linux containers), so I have to keep it as native as possible or using Bouncy Castle (which I'm still not sure if runs in Linux .NET Core).
I really appreciate your help!
I had faced a similar issue and found a solution. You'll have to use the PKCS11Interop.X509Store library.
The solution uses dotnet core native System.Security.Cryptography.X509Certificates.CertificateRequest::Create method
for generating a certificate.
As per the docs:
Pkcs11Interop is managed library written in C# that brings the
full power of PKCS#11 API to the .NET environment
Pkcs11Interop.X509Store is managed library built on top of
Pkcs11Interop. It's main goal is to provide easy to use PKCS#11 based
read-only X.509 certificate store that can be easily integrated with
standard .NET ecosystem.
Till v0.3.0, implementation for issuing a certificate (i.e signing a CSR) is not available.
With minor modifications in the PKCS11Interop library, I was able to sign the CSR.
Mentioned in Issue #30, the code is now added in the PKCS11Interop.X509Store library version 0.4.0.
The below code is taken from test cases for BasicEcdsaCertificateRequestTest. Test cases for RSA CertificateRequest are also there.
// Load PKCS#11 based store
using (var pkcs11Store = new Pkcs11X509Store(SoftHsm2Manager.LibraryPath, SoftHsm2Manager.PinProvider))
{
// Find signing certificate (CA certificate)
Pkcs11X509Certificate pkcs11CertOfCertificateAuthority = Helpers.GetCertificate(pkcs11Store, SoftHsm2Manager.Token1Label, SoftHsm2Manager.Token1TestUserEcdsaLabel);
// Generate new key pair for end entity
ECDsa ecKeyPairOfEndEntity = ECDsa.Create(ECCurve.NamedCurves.nistP256);
// Define certificate request
CertificateRequest certificateRequest = new CertificateRequest(
new X500DistinguishedName("C=SK,L=Bratislava,CN=BasicEcdsaCertificateRequestTest"),
ecKeyPairOfEndEntity,
HashAlgorithmName.SHA256);
// Define certificate extensions
certificateRequest.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
certificateRequest.CertificateExtensions.Add(new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false));
certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DigitalSignature, false));
// Issue X.509 certificate for end entity
X509Certificate2 certificateOfEndEntity = certificateRequest.Create(
pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.SubjectName,
X509SignatureGenerator.CreateForECDsa(pkcs11CertOfCertificateAuthority.GetECDsaPrivateKey()),
DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddDays(365),
new BigInteger(1).ToByteArray());
// Verify signature on X.509 certificate for end entity
Assert.IsTrue(CaCertSignedEndEntityCert(pkcs11CertOfCertificateAuthority.Info.ParsedCertificate.RawData, certificateOfEndEntity.RawData));
// Asociate end entity certificate with its private key
certificateOfEndEntity = certificateOfEndEntity.CopyWithPrivateKey(ecKeyPairOfEndEntity);
// Export end entity certificate to PKCS#12 file
string basePath = Helpers.GetBasePath();
string pkcs12FilePath = Path.Combine(basePath, "BasicEcdsaCertificateRequestTest.p12");
File.WriteAllBytes(pkcs12FilePath, certificateOfEndEntity.Export(X509ContentType.Pkcs12, "password"));
}
Hope this helps.
I am working on OIOSAML with ADFS 2.0. I need the IdP response to be signed as well as encrypted. Below is my understanding on how signing and encryption of SAML request and response works:
SP signs the request using its own certificate key (Key-1)
IdP verifies the request using SP's public key (Key-1)
IdP signs the response using its own certificate key (Key-2)
IdP encrypts the response assertion using certificate key provided by SP (Key-3)
SP verifies response using IdP's public key (Key-2)
SP decrypts the response assertion using its own private key (Key-3)
If I keep Key-1 and Key-3 same, everything works. As my keystore in OIOSAML has only one key.
But now I want to use separate keys for request signing and response encryption. It fails here.
Does OIOSAML support multiple keys in keystore?
If yes then how does it distinguish between signing and encryption keys?
This feature is available from OIOSAML release 3.
I need to make calls to a rest API service via BizTalk Send adapter. The API simply uses a token in the header for authentication/authorization. I have tested this in a C# console app using httpclient and it works fine:
string apiUrl = "https://api.site.com/endpoint/<method>?";
string dateFormat = "dateFormat = 2017-05-01T00:00:00";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("token", "<token>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
string finalurl = apiUrl + dateFormat;
HttpResponseMessage resp = await client.GetAsync(finalurl);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
var rootresult = JsonConvert.DeserializeObject<jobList>(result);
return rootresult;
}
else
{
return null;
}
}
however I want to use BizTalk to make the call and handle the response.
I have tried using the wcf-http adapter, selecting 'Transport' for security (it is an https site so security is required(?)) with no credential type specified and placed the header with the token in the 'messages' tab of the adapter configuration. This fails though with the exception: System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
I have tried googling for this specific scenario and cannot find a solution. I did find this article with suggestions for OAUth handling but I'm surprised that even with BizTalk 2016 I still have to create a custom assembly for something so simple.
Does anyone know how this might be done in the wcf-http send adapter?
Yes, you have to write a custom Endpoint Behaviour and add it to the send port. In fact with the WCF-WebHttp adapter even Basic Auth doesn't work so I'm currently writing an Endpoint Behaviour to address this.
One of the issues with OAuth, is that there isn't one standard that everyone follows, so far I've had to write 2 different OAuth behaviours as they have implemented things differently. One using a secret and time stamp hashed to has to get a token, and the other using Basic Auth to get a token. Also one of them you could get multiple tokens using the same creds, whereas the other would expire the old token straight away.
Another thing I've had to write a custom behaviour for is which version of TLS the end points expects as by default BizTalk 2013 R2 tries TLS 1.0, and then will fail if the web site does not allow it.
You can feedback to Microsoft that you wish to have this feature by voting on Add support for OAuth 2.0 / OpenID Connect authentication
Maybe someone will open source their solution. See Announcement: BizTalk Server embrace open source!
Figured it out. I should have used the 'Certificate' for client credential type.
I just had to:
Add token in the Outbound HTTP Headers box in the Messages tab and select 'Transport' security and 'Certificate' for Transport client credential type.
Downloaded the certificate from the API's website via the browser (manually) and installed it on the local servers certificate store.
I then selected that certificate and thumbprint in the corresponding fields in the adapter via the 'browse' buttons (had to scroll through the available certificates and select the API/website certificate I was trying to connect to).
I discovered this on accident when I had Fiddler running and set the adapter proxy setting to the local Fiddler address (http://localhost:8888). I realized that since Fiddler negotiates the TLS connection/certificate (I enabled tls1.2 in fiddler) to the remote server, messages were able to get through but not directly between the adapter and the remote API server (when Fiddler WASN'T running).
Can someone explain how do I compute a HMAC
===============
To verify that the request came from Shopify, compute the HMAC digest according to the following algorithm and compare it to the value in the X-Shopify-Hmac-SHA256 header. If they match, you can be sure that the Webhook was sent from Shopify and the data has not been compromised.
Each Webhook request includes a X-Shopify-Hmac-SHA256 header which is generated using the app's shared secret, along with the data sent in the request.
I have the secret key... how can I combine the secret key + the data in the request to generate a HMAC
The easiest way is to use the ShopifySharp Library. You can use the Nuget package and install it in your project.
This is an example taken from the ShopifySharp website for validating webhooks:
NameValueCollection requestHeaders = Request.Headers;
Stream inputStream = Request.InputStream;
if(AuthorizationService.IsAuthenticWebhook(requestHeaders, inputStream, shopifySecretKey))
{
//Webhook is authentic.
}
else
{
//Webhook is not authentic and should not be acted on.
}
If you don't want to use ShopifySharp, you can see how they implemented it in the source code.
I try to get a request token from Twitter OAuth and I always received a server error 401 when I try to get the response. I don't want to used an existing library because I try to learn Oauth and maybe build my own library. This is my simple code :
WebRequest request = WebRequest.Create("https://api.twitter.com/oauth/request_token");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
StringBuilder sbParams = new StringBuilder();
sbParams.Append("OAuth ");
sbParams.AppendFormat("oauth_consumer_key={0},", "[COMSUMERKEY]");
sbParams.AppendFormat("oauth_signature_method={0},", "PLAINTEXT");
sbParams.AppendFormat("oauth_signature={0},", HttpUtility.UrlEncode("[COMSUMER_SECRET]&"));
sbParams.AppendFormat("oauth_timestamp={0},", ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds).ToString());
sbParams.AppendFormat("oauth_nonce={0},", "asdfalkjpoijwpeonpoaisudfnpowieuyfpasosdfdn");
sbParams.AppendFormat("oauth_version={0},", "1.0");
sbParams.AppendFormat("oauth_callback={0}", HttpUtility.UrlEncode(Request.Url.ToString()));
request.Headers.Add("Authorization", sbParams.ToString());
// Get the response.
WebResponse response = request.GetResponse();
From http://oauth.net/core/1.0a/#http_codes You know these
HTTP 401 Unauthorized
Invalid Consumer Key
Invalid / expired Token
Invalid signature
Invalid / **used nonce
The "used nonce" thing may be a problem. You need to generate a random string. From http://oauth.net/core/1.0a/#nonce
A nonce is a random string, uniquely generated for each request
Onto the serious business. You are not supposed to transmit your consumer secret, once you ever received it! Many OAuth libraries have a
request_request_token(consumer_key,consumer_secret)
Despite appearances, the consumer_secret is never transmitted. It is used at client-side, for verification of server's response. (A similar verification occurs at server-side too)
And you dont put in any static values for signing requests. From http://oauth.net/core/1.0a/#signing_process
All Token requests and Protected Resources requests MUST be signed by the Consumer and verified by the Service Provider.
Bottomline: do read the http://oauth.net/core/1.0a/ article to see how the protocol works. And choose a hands-on OAuth library that doesnt abstract too much details (The oauth-php library I used came with SQL tables and managed data stores and session memory by itself).