2

During development we were using the Self Signed Certificate from IIS 8 for developing/testing Provider Hosted App we are working on.

Now we need to make changes to the app for Packaging and Publishing. I am following the MSDN documentation Package and publish high-trust apps for SharePoint 2013

I have made the changes in the project, as explained in the MSDN documentation but having issue in the TokenHelper.cs code

    private static X509SigningCredentials GetSigningCredentials(X509Certificate2 cert)
    {
        return (cert == null) ? null
                              : new X509SigningCredentials(cert,
                                                           SecurityAlgorithms.RsaSha256Signature,
                                                           SecurityAlgorithms.Sha256Digest);
    }

    private static X509Certificate2 GetCertificateFromStore()
    {
        if (string.IsNullOrEmpty(ClientSigningCertificateSerialNumber))
        {
            return null;
        }

        // Get the machine's personal store
        X509Certificate2 storedCert;
        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

        try
        {
            // Open for read-only access                 
            store.Open(OpenFlags.ReadOnly);

            // Find the cert
            storedCert = store.Certificates.Find(X509FindType.FindBySerialNumber,
                                                 ClientSigningCertificateSerialNumber,
                                                 true)
                           .OfType<X509Certificate2>().SingleOrDefault();
        }
        finally
        {
            store.Close();
        }

        return storedCert;
    }

I have the certificate show up in

  store.Certificates

but the Find method returns an empty collection. Because of which I am getting SigningCredentials was not initialized exception.

Things I verfied -

  1. Went through the steps twice, as mentioned in the MSDN documentation
  2. Checked the serial number in the web config is correct and all CAPs.
  3. Self Signed Certificate (.pfx) installed under Personal -> Certificates in Microsoft Certificate Store.

Note - I am doing these steps with Self Signed Certificate and once these steps are successful will be getting the commercial certificate from a CA and proceed to package the app.

  • 1
    What is the problem you are facing? – Unnie Jul 28 '15 at 11:38
  • I am getting SigningCredentials was not initialized exception. – bkk Jul 28 '15 at 11:57
3

I had that same issue. Certificate turned up when I used this:

foreach (var certificate in store.Certificates)
{
     if (certificate.SerialNumber.ToLower().Equals(ClientSigningCertificateSerialNumber))
     {
     storedCert = certificate;
     break;
     }
}

Update (original method, slightly changed):

//removes unwanted characters
string newString = new string(ClientSigningCertificateSerialNumber.Where(c => char.IsLetter(c) || char.IsDigit(c)).ToArray());
//use new string in find method
var storedCert = store.Certificates.Find(X509FindType.FindBySerialNumber, newString, true).OfType<X509Certificate2>().FirstOrDefault(); 

Checking ClientSigningCertificateSerialNumber's length gave me 33 instead of 32. The above code removes unwanted characters and gives the correct length of 32. Using this returns the correct certificate.

  • I just finished implementing this approach. Will update the code soon for others. – bkk Jul 28 '15 at 13:36
  • But can anyone point the real issue with the Find method? – bkk Jul 28 '15 at 13:37
  • @bkk, i haven't tried investigating it yet but you can put the same code in a console application and try to find out. – Akhoy Jul 28 '15 at 16:34
  • @bkk Find method wasn't working because of an unwanted character in the string. Check updated code with reason. – Akhoy Jul 30 '15 at 14:50
  • 1
    @Akhoy Thanks a lot. I spent days in fixing my AddIn finally you pointed out the right solution. When I was comparing SerialNumber by looking at it with my eyes it looks the same. I never checked the length but when I did it wasn't the same. Thanks again. – Ravi Khambhati Apr 13 '18 at 3:11
0

You can also do that by powershell, this is an example. https://msdn.microsoft.com/en-us/library/office/fp179901.aspx

0

So I found a way to solve my problem with this change to the tokenhelper code

    private static readonly string ClientSigningCertificatePath = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePath");
    private static readonly string ClientSigningCertificatePassword = WebConfigurationManager.AppSettings.Get("ClientSigningCertificatePassword");
    private static readonly X509Certificate2 ClientCertificate = (string.IsNullOrEmpty(ClientSigningCertificatePath) || string.IsNullOrEmpty(ClientSigningCertificatePassword)) ? null : new X509Certificate2(ClientSigningCertificatePath, ClientSigningCertificatePassword);
    private static readonly string ClientSigningCertificateSerialNumber = WebConfigurationManager.AppSettings.Get("ClientSigningCertificateSerialNumber");
    private static readonly X509SigningCredentials SigningCredentials = GetSigningCredentials(GetCertificateFromStore());

    private static X509SigningCredentials GetSigningCredentials(X509Certificate2 cert)
    {
        return (cert == null) ? null 
                              : new X509SigningCredentials(cert, SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest);
    }

    private static X509Certificate2 GetCertificateFromStore()
    {
        if (string.IsNullOrEmpty(Convert.ToString(ClientSigningCertificateSerialNumber)) && ClientCertificate != null)
        {
            return ClientCertificate;
        }

        // Get the machine's personal store
        X509Certificate2 storedCert = null;
        X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

        try
        {
            // Open for read-only access                 
            store.Open(OpenFlags.ReadOnly);

            foreach (var cert in store.Certificates)
            {
                var serialNumber = cert.SerialNumber;
                if (ClientSigningCertificateSerialNumber.Equals(serialNumber, StringComparison.InvariantCultureIgnoreCase))
                {
                    storedCert = cert;
                    break;
                }
            }
        }
        finally
        {
            store.Close();
        }

        return storedCert;
    }

In this code I have handled the Find method issue and also built in logic for continuing to use ClientSigningCertificatePath and ClientSigningCertificatePassword for developers in the team.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.