CodeGuru
Earthweb Search
Forums Wireless Jars Gamelan Developer.com
CodeGuru Navigation
RSS Feeds

RSSAll

RSSVC++/C++

RSS.NET/C#

RSSVB

See more EarthWeb Network feeds

follow us on Twitter

Member Sign In
User ID:
Password:
Remember Me:
Forgot Password?
Not a member?
Click here for more information and to register.

Become a Marketplace Partner

jobs.internet.com

internet.commerce
Partners & Affiliates
















Home >> Visual C++ / C++ >> Internet & Networking >> Internet Protocols >> Security


Security Certificates Treatment with CryptoAPI
Rating:

Kiko Vives (view profile)
October 2, 2003

Environment: VC6

Introduction

A few months ago, I needed to program a complete installation for a VPN access (IPSEC\L2TP) for clients with Microsoft Windows systems (98, ME, 2000, and XP). This included RAS access (creating the access, dialing control, and so forth), IPSec and L2TP aspects (enabling ipsec and l2tp, security policies, and so on), registry operations, and certificate treatment.


(continued)



The most difficult point was the certificate treatment because there is not too much information related to that. Finally, I wrote a software (using CryptoAPI) that adds any certificate to any store in any Microsoft operating system (Windows 98 or higher).

Project

One of the greatest issues about this is the versions of the libraries and headers used. So, the first thing to do was to update the SDK and get the lastest files. Anyway, the updated files that I finally used (cypt32.lib, wincrypt.h, and BasesTD.h) are in the zip archive with the project files; so, if you want to compile the project, first you have to rename the original files in the VC6 directory (C:\Program files\Microsoft Visual Studio\VC98\Include and Lib) to, for example, "crypt32_old.lib, wincrypt_old.h, basestd_old.h" and saving this one there.

For my project, I had to import two certificates. One was the CA certificate (public and binary); the other one was the personal certificate, which was encrypted with a password that only the owner of the certificate knew (both of them were OpenSSL certificates). I am going to explain the second one:

To add the personal certificate to the personal system store, I wrote the 'ImportPerCert' function that imports the certificate indicated by 'm_pathPer' (which is a mapped variable from an edit text box) to the Personal system store. This function returns 1 if everything has gone okay or 0 in other cases.

How does this work? First, we make a 'Blob'—a structure that holds an array of bytes; in our case, containing the view of the certificate. After that, we check that it is a valid certificate with the 'PFXIsPFXBlob' function. If so, we use the 'PFXImportCertStore' function, which returns a handle to the store of the certificate decrypted with the password. Now, we get the handle to the store where we want to put the certificate by using the 'CertOpenStore' function and specifying the personal store (L"My"). Whenever certificates exist in the store (the 'CertEnumCertificatesInStore' function), we import them with 'CertAddCertificateContextToStore'.

This was my main goal, but once you have this info, you can do whatever you want with these certificates. For example, if we want to get the date when the certificate will be invalid, we can do:

PCERT_INFO pinfo;
pinfo = pctx->pCertInfo;
SYSTEMTIME date;
FileTimeToSystemTime(&(pinfo->NotAfter), &date);

where 'pctx' is the context of the certificate returned by the 'CertEnumCertificatesInStore' function.

Finally, if the operating system is Windows 98 (or SE, or ME), you have to substitute the instructions where indicated in the code.

You can see the 'ImportPerCert' function below:

int CCertImportDlg::ImportPerCert()
{
  HANDLE hfile          = INVALID_HANDLE_VALUE;
  HANDLE hsection       = 0;
  void* pfx             = 0;
  HCERTSTORE pfxStore   = 0;
  HCERTSTORE hFileStore = 0;
  HCERTSTORE myStore    = 0;
  PCCERT_CONTEXT pctx   = 0;
  bool recognizedPFX;

  UpdateData(true);

  // get the handle to the file...
  hfile = CreateFile(m_pathPer, FILE_READ_DATA, FILE_SHARE_READ,
                     0, OPEN_EXISTING, 0, 0);

  // FOR WINDOWS 98
  // hfile = CreateFile(ruta , GENERIC_READ, FILE_SHARE_READ, 0,
  //                    OPEN_EXISTING, 0, 0);

  if (INVALID_HANDLE_VALUE == hfile)
  {
    AfxMessageBox("Certificate not found. Check that the path
                   indicated is correct.", MB_ICONERROR);
    return 0;
  }

  // now, we create a file mapping object for that file
  hsection = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0);

  if (!hsection)
  {
    AfxMessageBox("Error in 'CreateFileMapping'", MB_ICONERROR);
    FreeHandles(hfile, hsection, hFileStore, pfx, pctx, pfxStore,
                myStore);
    return 0;
  }

  // we map a view of the file that we previously opened into pfx
  pfx = MapViewOfFile(hsection, FILE_MAP_READ, 0, 0, 0);

  if (!pfx)
  {
    AfxMessageBox("Error in 'MapViewOfFile'", MB_ICONERROR);
    FreeHandles(hfile, hsection, hFileStore, pfx, pctx, pfxStore,
                myStore);
    return 0;

  }

  // and with that view we make a blob ...
  CRYPT_DATA_BLOB blob;
  blob.cbData   = GetFileSize(hfile, 0);
  blob.pbData   = (BYTE*)pfx;
  recognizedPFX = false;

  try
  {
    // ... and after we try to decode that blob to see whether
    // pfx is recognized...
    if (PFXIsPFXBlob(&blob))
      recognizedPFX = true;
  }

  catch (...)
  {
  }

  if (!recognizedPFX)
  {
    AfxMessageBox("This certificate is not valid.", MB_ICONERROR);
    FreeHandles(hfile, hsection, hFileStore, pfx, pctx, pfxStore,
                myStore);
    return 0;
  }

  wchar_t password[128];

  // We get the password that the user typed in the edit box...
  GetPassword(password);

  // We import the certificate store from the blob. I needed it
  // to be exportable...
  pfxStore = PFXImportCertStore(&blob, password,
                                CRYPT_MACHINE_KEYSET |
                                CRYPT_EXPORTABLE);

  // FOR WINDOWS 98, the flag CRYPT_MACHINE_KEYSET is not valid
  // pfxStore = PFXImportCertStore(&blob, password,
  //                               CRYPT_EXPORTABLE);

  if (!pfxStore)
  {
    AfxMessageBox("Error in PFXImportCertStore. Probably password
                   incorrect.", MB_ICONERROR);
    FreeHandles(hfile, hsection, hFileStore, pfx, pctx, pfxStore,
                myStore);
    return 0;
  }

  // and we open the certificate store where we want to save
  // the certificate
  // I chose "My" for the personal store...
  myStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
                          CERT_STORE_OPEN_EXISTING_FLAG |
                          CERT_SYSTEM_STORE_LOCAL_MACHINE, L"MY");

  // FOR WINDOWS 98
  // myStore = CertOpenSystemStore(NULL, L"MY");

  if (!myStore)
  {
    AfxMessageBox("Error in 'CertOpenSystemStore'", MB_ICONERROR);
    FreeHandles(hfile, hsection, hFileStore, pfx, pctx, pfxStore,
                myStore);
    return 0;
  }


  // while certificates exist in the pfxStore store....
  while (0 != (pctx = CertEnumCertificatesInStore(pfxStore, pctx)))
  {

    wchar_t name[128];

    // we get the friendly name of the certificate...
    if (!CertGetNameString(pctx, CERT_NAME_FRIENDLY_DISPLAY_TYPE,
                           0, 0, name, sizeof name / sizeof *name))
    {
      AfxMessageBox("Error in 'CertGetNameString'", MB_ICONERROR);
    }

    // and we try to add it to the store gotten before with
    // CertOpenStore
    if (!CertAddCertificateContextToStore(myStore, pctx,
         CERT_STORE_ADD_NEW, 0))
    {
      DWORD err = GetLastError();

      // Maybe there's another equal certificate already added
      if (CRYPT_E_EXISTS == err)
      {
        if(AfxMessageBox("An equivalent previous personal
                          certificate already exists. Overwrite?
                          (Yes/No)", MB_YESNO) == IDYES)
        {
          if (!CertAddCertificateContextToStore(myStore, pctx,
               CERT_STORE_ADD_REPLACE_EXISTING, 0))
          {
            AfxMessageBox("Error in
                           'CertAddCertificateContextToStore'",
                            MB_ICONERROR);
            FreeHandles(hfile, hsection, hFileStore, pfx, pctx,
                        pfxStore, myStore);
            return 0;
          }
        }
      }
      else
      {
        AfxMessageBox("Error in
                       'CertAddCertificateContextToStore'",
                       MB_ICONERROR);
        FreeHandles(hfile, hsection, hFileStore, pfx, pctx,
                    pfxStore, myStore);
        return 0;
      }
    }
  }

  return 1;
}

Downloads

Download demo project - 9 Kb
Download source - 153 Kb

Tools:
Add www.codeguru.com to your favorites
Add www.codeguru.com to your browser search box
IE 7 | Firefox 2.0 | Firefox 1.5.x
Receive news via our XML/RSS feed







RATE THIS ARTICLE:   Excellent  Very Good  Average  Below Average  Poor  

(You must be signed in to rank an article. Not a member? Click here to register)

Latest Comments:
Private keyID - DSkrypka (12/14/2005)
Excellent article - vijay_visana (08/24/2004)
any good reference for CryptoAPI? books please - Legacy CodeGuru (10/07/2003)

View All Comments
Add a Comment:
Title:
Comment:
Pre-Formatted: Check this if you want the text to display with the formatting as typed (good for source code)



(You must be signed in to comment on an article. Not a member? Click here to register)

internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

Jupitermedia Corporate Info

Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

Whitepapers and eBooks

Intel Whitepaper: Comparing Two- and Four-Socket Platforms for Server Virtualization
IBM Solutions Brief: Go Green With IBM System xTM And Intel
HP eBook: Simplifying SQL Server Management
IBM Contest: Are You the Next Superstar? Join the "Search for the XML Superstar" Contest to Find Out
Microsoft PDF: Top 10 Reasons to Move to Server Virtualization with Hyper-V
Microsoft PDF: Six Reasons Why Microsoft's Hyper-V Will Overtake Vmware
Microsoft Step-by-Step Guide: Hyper-V and Failover Clustering
Intel PDF: Quad-Core Impacts More Than the Data Center
Intel PDF: Virtualization Delivers Data Center Efficiency
Go Parallel Article: PDC 2008 in Review
Microsoft PDF: Top 11 Reasons to Upgrade to Windows Server 2008
Avaya Article: Communication-Enabled Mashups: Empowering Both Business Owners and IT
Intel Whitepaper: Building a Real-World Model to Assess Virtualization Platforms
  PDF: Intel Centrino Duo Processor Technology with Intel Core2 Duo Processor
Microsoft Article: Build and Run Virtual Machines with Hyper-V Server 2008
Go Parallel Article: Q&A with a TBB Junkie
IBM Whitepaper: Innovative Collaboration to Advance Your Business
Internet.com eBook: Real Life Rails
IBM eBook: The Pros and Cons of Outsourcing
Internet.com eBook: Best Practices for Developing a Web Site
IBM CXO Whitepaper: The 2008 Global CEO Study "The Enterprise of the Future"
Avaya Article: Call Control XML in Action - A CCXML Auto Attendant
IBM CXO Whitepaper: Unlocking the DNA of the Adaptable Workforce--The Global Human Capital Study 2008
Adobe Acrobat Connect Pro: Web Conferencing and eLearning Whitepapers
HP eBook: Guide to Storage Networking
MORE WHITEPAPERS, EBOOKS, AND ARTICLES