0
votes

I have created web api and tried to issue GET request using c# as follow

namespace APIMCheck
{
 class Program
 {
    static void Main(string[] args)
    {
        string thumbprint = "***"; 
        string url @"https://******-us-stats-webapi.azurewebsites.net/statistics/v1/masterData/carTypes";


        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);

        X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true);
        X509Certificate2 certificate = certificates[0];
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
        ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);


        req.ClientCertificates.Add(certificate);
        req.Method = WebRequestMethods.Http.Get;

        Console.WriteLine(Program.CallAPI(req).ToString());

        Console.Read();

    }

    public static string CallAPI(HttpWebRequest req)
    {
        var httpResponse = (HttpWebResponse)req.GetResponse();

        using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
        {
            return streamReader.ReadToEnd();
        }
    }

    public static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        return true;
    }
  }
}

I get response with data. All good.

Now, I have created Azure APIM, which will act as front end for above web API

This is policy configured in Azure API Management portal

<policies>
  <inbound>
    <base />
      <choose>
        <when condition="@(context.Request.Certificate.Verify() != true || context.Request.Certificate == null || context.Request.Certificate.Issuer != "CN=MySubCA, DC=MYEXT, DC=NET" || context.Request.Certificate.NotAfter < DateTime.Now)">
            <return-response>
                <set-status code="403" reason="Invalid client certificate" />
                <set-body template="none">@(context.Request.Certificate.Issuer.ToString())</set-body>
            </return-response>
        </when>
    </choose>
    </inbound>
    <backend>
     <base />
    </backend>
    <outbound>
     <base />
    </outbound>
    <on-error>
     <base />
    </on-error>
</policies>

Now, changed the url as follow to point apim

 string url = @"https://******-us-stats-apim.azure-api.net/statistics/v1/masterData/carTypes";

I get below error

The request was aborted: Could not create SSL/TLS secure channel for HttpWebRequest

How SSL/TLS making difference in web api and APIM?

Anything to do with firewall?

2

2 Answers

1
votes

By default, TLS 1.2 is enabled for Azure API Management gateway.

You could go to your azure api management(on portal) > Protocol settings> turn on tls 1.2 and ssl 3.0.

enter image description here

0
votes

There are a few things you do in your test app and APIM cannot do on it's own:

  1. Enable SSL3
  2. Add client certificate
  3. Ignore any SSL validation errors.

Of the things above only #2 is fine to have in production. SSL3 is deprecated and should not be used in production. Ignoring any SSL errors is also unwise, since that way you cannot be sure that you're talking to your server.

Now assuming that you're fine with all of the above:

  1. For SSL3 follow @Joey Cai answer.
  2. To allow APIM to use your certificate to authenticate to backend follow this guidance: https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates
  3. To control SSL validation at APIM level use this REST API: https://docs.microsoft.com/en-us/rest/api/apimanagement/2019-01-01/backend/createorupdate and set-backend-service policy.

The main reason for #2 and #3 is that client-to-APIM and APIM-to-backend are two separate connections. So when APIM needs to make a call to backend it must have client certificate available (if it's required by backend). That also means that by default APIM will not require client to provide certificate.