locked
How to use CryptoAPI to download root CA on the fly RRS feed

  • Question

  • In Windows 7 SP1 there's a new behavior that the OS comes with a minimal set of Root Certificates and when the CryptoAPI encounters a new root certificate it know how to add it to the list.

    I have an application that uses SSL communication, I want after I get the cert to be able to use CryptoAPI to verify that the root certificate is valid, I already know how to do this using the CA root store, what I need is the ability to tell CryptoAPI to get the root certificate from the Internet and install it in the root store, just like Internet Explorer 9 is doing under Windows 7 SP1

    Wednesday, August 10, 2011 2:30 PM

All replies

  • I think the behavior of CryptoAPI that you are referring to is that the root store has a small number of root certs. However, there are other root certs "baked" into the OS as resources. When an application does a chain build, CryptoApi will look in the root store and it will also look at those roots that are baked into the OS. If the root is in the resources then it will get automatically added to the root store of the machine and you will be able to "see" it together with other root certs.

    This is probably what you are seeing with Internet Explorer.

    If there is some cert somewhere on the internet that you want to be trusted then you need to explicitly go and get it and add it to the root store. There does not exist a single CryptoAPI function to do this. Have a look at CryptRetrieveObjectByUrl and CertAddCertificateContextToStore.

     

    Andrew

    Wednesday, August 10, 2011 4:39 PM
  • Hi,

    Where can I see those "baked" roots certs?

    Thanks,

    Barak

    Wednesday, August 10, 2011 7:22 PM
  • Hi,

    I took things a step further, I have this crypto code, if the root cert is present the cert is validated, if the root cert is not present then I'll get an error. If I take the .cer certificate on that machine and double click it then it will get the root certificate into the store. So I'm wrong with my code somewhere:

    bool VerifyChainUsingCrypto(const char* pChain,
              DWORD dwChainSize)
    {
     //Open the IE store
     HCERTSTORE hStore=CertOpenSystemStore(NULL,
                "ROOT");

     //Do we have the store?
     if (!hStore)
     {
      //Exit
      return false;
     }

     //The cert engine config
     CERT_CHAIN_ENGINE_CONFIG aConf;
     memset(&aConf,
         0,
         sizeof(aConf));

     //Set the data
     aConf.cbSize=sizeof(CERT_CHAIN_ENGINE_CONFIG);
     aConf.hRestrictedRoot=hStore;
     aConf.dwFlags=CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE;

     //Create the cert engine
     HCERTCHAINENGINE hEng=NULL;
     if (!CertCreateCertificateChainEngine(&aConf,
                &hEng))
     {
      //Close the store
      CertCloseStore(hStore,
            0);
      //Exit
      return false;
     }

     //Build the cert
     PCCERT_CONTEXT pCert;
     pCert=CertCreateCertificateContext(X509_ASN_ENCODING,
                (const BYTE*)pChain,
                dwChainSize);

     //Do we have it?
     if (!pCert)
     {
      //Close the store
      CertCloseStore(hStore,
            0);

      //Close the cert eng
      CertFreeCertificateChainEngine(hEng);

      //Exit
      return false;
     }

     //Build chain
     CERT_CHAIN_PARA aPara;
     memset(&aPara,
         0,
         sizeof(aPara));

     aPara.cbSize=sizeof(aPara);
     aPara.RequestedUsage.dwType=USAGE_MATCH_TYPE_AND;
     
     //Try to verify the chain
     PCCERT_CHAIN_CONTEXT pCertChain;
     if (!CertGetCertificateChain(hEng,
             pCert,
             NULL,
             hStore,
             &aPara,
             0,
             NULL,
             &pCertChain))
     {
      //Free the cert
      CertFreeCertificateContext(pCert);

      //Close the store
      CertCloseStore(hStore,
            0);

      //Exit
      return false;
     }

     //Check the chain status
     bool bResult=(!(pCertChain->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED) &&
          pCertChain->TrustStatus.dwErrorStatus==CERT_TRUST_NO_ERROR);

     //Cleanup
     CertFreeCertificateChain(pCertChain);
     CertFreeCertificateContext(pCert);
     CertFreeCertificateChainEngine(hEng);
     CertCloseStore(hStore,
            0);

     //Done
     return bResult;
    }

    Thanks,

    Barak

    Thursday, August 11, 2011 2:25 PM
  • Hi,

    Managed to get it working, if I remove the store and certificate chain engine.

    Thanks,

    Barak

    Thursday, August 11, 2011 3:00 PM
  • You can view the baked in roots by looking at resources of crypt32.dll. Open crypt32.dll with Visual Studio.

    You will see some resources. Look at AUTHROOTS and UPDROOTS. Export them to a file.

    Then run certutil -dump on each file and you will see the root certs that are baked into the OS.

    My understanding is that when you verify a cert and it chains to a root that cannot be found in the root store then by default Windows will try to goto Windows Update to see if the root cert is there. If Windows Update cannot be contacted then the chain engine will look at the "baked" in roots.

    Hope that helps explain things for you,

    Andrew

    Thursday, August 11, 2011 6:29 PM
  • You basically want to programmatically get a certificate, trust it and install it into a root store? How would that be secure coding? An attacker could do the same, right? The Windows pathway that does this is not available to your calling code.
    Monday, August 15, 2011 6:37 PM