IIS https hosting - to get mmc installed certificate by code - azure

I got success in checking cert is present in my current user by local execution process. But when I publish the same code on IIS, I am unable to get a certificate.
Please guide changes in code or settings for code publish on IIS.
using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
string certThumbprint = "E661583E8FABEF4C0BEF694CBC41C28FB81CD870";
bool validOnly = false;
using (X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
certStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
// Replace below with your certificate's thumbprint
certThumbprint,
validOnly);
// Get the first cert with the thumbprint
X509Certificate2 cert = certCollection.OfType<X509Certificate>().FirstOrDefault();
if (cert is null)
throw new Exception($"Certificate with thumbprint {certThumbprint} was not found");
// Use certificate
Console.WriteLine(cert.FriendlyName);
// Consider to call Dispose() on the certificate after it's being used, available in .NET 4.6 and later
}

Related

Azure app services does it have a certificate store?

I have a project that communicates with a client server, the client server sends a self-signed certificate and I should trust him in order the continue the connection.
private bool VerifyServerCertificate(LdapConnection ldapConnection, X509Certificate certificate)
{
foreach (var cert in CertificateFileNames)
{
var certPath = Directory.GetFiles($#"{AppDomain.CurrentDomain.BaseDirectory}", $"{cert}",System.IO.SearchOption.AllDirectories);
X509Store store = new X509Store(StoreName.TrustedPeople, StoreLocation.CurrentUser);
try
{
if (File.Exists(certPath.FirstOrDefault()))
{
var certToAdd = new X509Certificate2(X509Certificate.CreateFromCertFile(certPath.FirstOrDefault()));
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, certToAdd.SubjectName.Name, true);
if (certs.Count.Equals(0))
{
store.Open(OpenFlags.ReadWrite);
store.Add(new X509Certificate2(X509Certificate.CreateFromCertFile(cert)));
store.Close();
}
}
}
catch
{
throw new Exception("Cannot install the certificate.");
}
}
X509Certificate2 certificate2 = new X509Certificate2(certificate);
return certificate2.Verify();
}
This works fine but the project needs to be deployed as a Azure app service. So my question is, the app service environment does it have a "Trusted People" storage ?
The method receives de X509certificate from the connection and verify against the trusted people storage so I need to install the certificates before the validation.
Thanks.

Azure web app "ERR: Cert with thumbprint: ...' not found in local machine cert store."

I'm trying to use an Apple push certificate in an Asp.NET Core 1.1 app but it cannot find any certificates.
I uploaded the cert and set WEBSITE_LOAD_CERTIFICATES to *(all).
The following code is what I use to get the certificate
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (signingCert.Count == 0)
{
throw new FileNotFoundException(string.Format("Cert with thumbprint: '{0}' not found in local machine cert store.", thumbprint));
}
return signingCert[0];
}
What am I missing?
It seems that you'd like to upload your certificate to the certificates collection in Azure Websites and consume it in your web application from your site’s personal certificate store. I'm upload my certificate and use the following code to consume it in Asp.NET Core 1.1 app, the code works for me.
X509Certificate2 retVal = null;
var thumbprint = "{cert_thumbprint}";
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certCollection = store.Certificates;
var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
if (signingCert.Count > 0)
{
retVal = signingCert[0];
}
Remote debug the code and the code works fine on azure website

X509CertificateCollection problems in an Azure webjob

We are developing an Azure webjob that needs to communicate to several servers, each one of them demanding a separate SSL connection.
We have our certificates stored in an external server and load them at runtime together with the corresponding SSL connection settings. When we invoke the X509Certificate2 constructor in order to add it to the X509CertificateCollection, the webjob gets stopped with exit code -1073740940 and its status becomes "PendingRestart". Our guess is that the X509Certificate2 class is not compatible with webjobs, but we cannot find any hint on how to tackle this issue.
The code line that generate the issue is-
new X509Certificate2(sslCertificateBytes,
socketSettings_.CertificatePassword))
private X509CertificateCollection GetClientCertificates(byte[] sslCertificateBytes)
{
log_?.OnEvent($"{nameof(SSLStreamFactory)} function {nameof(GetClientCertificates)} started");
X509CertificateCollection result = new X509Certificate2Collection();
log_?.OnEvent($"{nameof(X509CertificateCollection)} {nameof(result)} construction successfull");
try
{
if (sslCertificateBytes != null)
{
log_?.OnEvent($"{nameof(sslCertificateBytes)} enumerable != null");
result.Add(new X509Certificate2(sslCertificateBytes, socketSettings_.CertificatePassword));
log_?.OnEvent($"result.Add successful");
}
else if (!string.IsNullOrEmpty(socketSettings_.CertificatePath))
{
log_?.OnEvent($"{nameof(socketSettings_.CertificatePath)} != null");
result = new X509Certificate2Collection();
log_?.OnEvent($"{nameof(X509CertificateCollection)} {nameof(result)} construction successfull");
var clientCert = StreamFactory.LoadCertificate(socketSettings_.CertificatePath, socketSettings_.CertificatePassword, log_);
log_?.OnEvent($"{nameof(StreamFactory.LoadCertificate)} function ended");
if (clientCert != null)
{
result.Add(clientCert);
log_?.OnEvent($"result.Add successful");
}
}
}
catch (Exception ex)
{
log_?.OnEvent($"{nameof(SSLStreamFactory)} function {nameof(GetClientCertificates)} raised exception: {ex.Message}");
throw;
}
log_?.OnEvent($"{nameof(SSLStreamFactory)} function {nameof(GetClientCertificates)} ended");
return result;
}
Is there a way to manage SSL certificates on Azure Webjobs?
Thanks in advance
Azure webjobs run into the same environment of its parent webapp. You can follow this article to import certificates into a webapp :
Using Certificates in Azure Websites Applications
In a nutshell:
Upload the certificate to Azure.
Add an app setting called WEBSITE_LOAD_CERTIFICATES with its value set to the thumbprint of the certificate (make it accessible to your web application)
Important thing to remember:
The certificates will be installed to the Personal certificate store of the ApplicationPool Identity of the worker process.
So to access the certificate from your webapp or webjob:
var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
// Replace below with your cert's thumbprint
"E661583E8FABEF4C0BEF694CBC41C28FB81CD870",
false);
// Get the first cert with the thumbprint
if (certCollection.Count > 0)
{
X509Certificate2 cert = certCollection[0];
}
certStore.Close();

Creating Azure Traffic Manager through REST API - unexpected behaviour

I created Traffic Manager throught its REST API using 2011-10-01 MS verion.
Resources I followed -
Create Profile -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758254.aspx
Create Definition -
http://msdn.microsoft.com/en-us/library/windowsazure/hh758257.aspx
Traffic Manager got created successfully. All happies.
But after 30mins of time, traffic manager is going to INACTIVE status and all its endpoints are GONE. It shows there are no endpoints associated with it.
I am not sure what is happening around. Is it Azure problem? or is it REST API problem? or is it my way of creating Traffic manager problem.
PS - I followed this sample for making REST API calls - http://msdn.microsoft.com/en-us/library/windowsazure/gg651127.aspx
Any help would be highly appreciated.
UPDATE1
Parameters
SubscriptionID - a Valid GUID from publishsettings
Certificate - I cross checked a valid certificate present in the local cert store
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name - JASH23.CLOUDAPP.NET
There is no error at REST API calls level. Everything worked seamlessly.
Profile Creation -
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Profile xmlns=""http://schemas.microsoft.com/windowsazure""><DomainName>" + ProfileDomain + "</DomainName><Name>" + ProfileName + "</Name></Profile>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
Definition Creation-
// X.509 certificate variables.
X509Store certStore = null;
X509Certificate2Collection certCollection = null;
X509Certificate2 certificate = null;
// Request and response variables.
HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;
// Stream variables.
Stream responseStream = null;
StreamReader reader = null;
// URI variable.
Uri requestUri = null;
// The thumbprint for the certificate. This certificate would have been
// previously added as a management certificate within the Windows Azure management portal.
string thumbPrint = CertificateThumbprint;
// Open the certificate store for the current user.
certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
certStore.Open(OpenFlags.ReadOnly);
// Find the certificate with the specified thumbprint.
certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
thumbPrint,
false);
// Close the certificate store.
certStore.Close();
// Check to see if a matching certificate was found.
if (0 == certCollection.Count)
{
throw new Exception("No certificate found containing thumbprint " + thumbPrint);
}
// A matching certificate was found.
certificate = certCollection[0];
// Create the request.
requestUri = new Uri("https://management.core.windows.net/"
+ SubscriptionId
+ "/services/WATM/profiles/" + ProfileName + "/definitions");
httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(requestUri);
// Add the certificate to the request.
httpWebRequest.ClientCertificates.Add(certificate);
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("x-ms-version", "2011-10-01");
string str = #"<Definition xmlns=""http://schemas.microsoft.com/windowsazure""><DnsOptions><TimeToLiveInSeconds>300</TimeToLiveInSeconds></DnsOptions><Monitors><Monitor><IntervalInSeconds>30</IntervalInSeconds><TimeoutInSeconds>10</TimeoutInSeconds><ToleratedNumberOfFailures>3</ToleratedNumberOfFailures><Protocol>HTTP</Protocol><Port>80</Port><HttpOptions><Verb>GET</Verb><RelativePath>/</RelativePath><ExpectedStatusCode>200</ExpectedStatusCode></HttpOptions></Monitor></Monitors><Policy><LoadBalancingMethod>RoundRobin</LoadBalancingMethod><Endpoints><Endpoint><DomainName>" + PrimaryService + "</DomainName><Status>Enabled</Status></Endpoint><Endpoint><DomainName>" + SecondaryService + "</DomainName><Status>Enabled</Status></Endpoint></Endpoints></Policy></Definition>";
byte[] bodyStart = System.Text.Encoding.UTF8.GetBytes(str.ToString());
Stream dataStream = httpWebRequest.GetRequestStream();
dataStream.Write(bodyStart, 0, str.ToString().Length);
// Make the call using the web request.
httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
// Parse the web response.
responseStream = httpWebResponse.GetResponseStream();
reader = new StreamReader(responseStream);
// Close the resources no longer needed.
httpWebResponse.Close();
responseStream.Close();
reader.Close();
UPDATE2
Once the TM went into Inactive State, I checked the profile definition using REST API. In there I was not able to find any endpoints. They are missing.
<Definitions xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Definition>
<DnsOptions>
<TimeToLiveInSeconds>300</TimeToLiveInSeconds>
</DnsOptions>
<Status>Enabled</Status>
<Version>1</Version>
<Monitors>
<Monitor>
<IntervalInSeconds>30</IntervalInSeconds>
<TimeoutInSeconds>10</TimeoutInSeconds>
<ToleratedNumberOfFailures>3</ToleratedNumberOfFailures>
<Protocol>HTTP</Protocol>
<Port>80</Port>
<HttpOptions>
<Verb>GET</Verb>
<RelativePath>/</RelativePath>
<ExpectedStatusCode>200</ExpectedStatusCode>
</HttpOptions>
</Monitor>
</Monitors>
<Policy>
<LoadBalancingMethod>Performance</LoadBalancingMethod>
<Endpoints/>
<MonitorStatus>Inactive</MonitorStatus>
</Policy>
</Definition>
</Definitions>
UPDATE3
This sporadic behavior is ONLY happening with the specific cloud services and TM profile/definitiona. When I create new set of cloud services and TM profile, then everything seems to be working fine. I tested this multiple times. So the only problem is with following parameters.
endpoint1 domain name - JASH13.CLOUDAPP.NET
endpoint2 domain name -JASH23.CLOUDAPP.NET
TM Domain - ramitm.trafficmanager.net
TM profilename - ramitm
This seems like some DNS Problems for very fast REST API Operations. I was not able to get the crux of the problem, but this is how I solved it.
Previously I was getting this problem for this patter - Create -> Delete -> Re-Create
Now I made it this way - Create -> Delete -> Delay -> Re-Create
I think by introducing delay component, I am giving enough time for Azure to settle down all the DNS and infrastructure and there by update them. So after introducing delay, I was not experiencing the problem. Delay can be 5 - 10 mins.

How to use X509Certificate2 as the credentials for a SharePointService request

I have a MOSS 2007 farm that requires a client certificate to access. I have written several methods that use the built in SharePoint services to retrieve data from the site. However, outside of my local test environment everything requires a client cert to access the services.
My method for retrieving the cert is:
private static X509Certificate2 GetCertCreds()
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(X509FindType.FindBySubjectKeyIdentifier, "SiteIdentityCertificateSerialNumber", true);
Assert.IsNotNull(certs);
return certs[0];
}
finally
{
store.Close();
}
}
Then in use I have to have something LIKE:
using (ListsServiceProxy.Lists service = new ListsServiceProxy.Lists())
{
service.Crendentials = GetCredentials();
XmlNode idResultsNode = service.GetListItems(documentLibraryName, null, queryNode, viewNode, "1", optionNode, null);
}
This is not compiling because of the type mismatch. Am I going about this the wrong way? If not is there a way to use the certificate as the services credentials? I think in end what I'm trying to do is convert an X509Certificate2 to ICredentials. Any help or advice would be greatly appreciated.
It turns out I had it all wrong. To correctly do this I replaced:
service.Credentials = GetCertCreds()
with
service.ClientCertificates.Add(GetCretCreds());
Adding the certificate into the service's client certificates collection is all that needed to happen.

Resources