Example C Program: Serializing Certificates
The following example demonstrates serializing a certificate context and its properties into a form that can be stored in a file, sent with an email message, or otherwise transmitted to another user. The example also shows how the serialized certificate can be changed back into a certificate and added to a certificate store. The same process works also with CRLs and CTLs using CertSerializeCRLStoreElement and CertSerializeCTLStoreElement.
This example illustrates the following tasks and CryptoAPI functions:
- Opening a system certificate store using CertOpenSystemStore.
- Opening a certificate store using CertOpenStore.
- Retrieving a certificate from a store using CertEnumCertificatesInStore.
- Getting the name of the certificate's subject using CertGetNameString.
- Creating a serialized form of a certificate context and its properties using CertSerializeCertificateStoreElement.
- Creating a new certificate from a serialized string and adding it into a certificate store using CertAddSerializedElementToStore.
- Using CertAddEncodedCertificateToStore to create a new certificate from the encoded portion of an existing certificate.
- Using CertCloseStore to close a certificate store.
//------------------------------------------------------ // Copyright (C) Microsoft. All rights reserved. // Example that uses CertSerializeCertificateStoreElement to // serialize the data from a certificate, // and CertAddSerializedElementToStore to add that data as a new // certificate to a store. // CertAddEncodeCertificateToStore is also demonstrated. #pragma comment(lib, "crypt32.lib") #include <stdio.h> #include <windows.h> #include <Wincrypt.h> #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) void MyHandleError(char *s); void main(void) { //------------------------------------------------------------------- // Declare and initialize variables. HCERTSTORE hSystemStore; HCERTSTORE hFileStore; PCCERT_CONTEXT pCertContext = NULL; char pszNameString[256]; BYTE* pbElement; DWORD cbElement; //------------------------------------------------------------------- // Open a system certificate store. if(hSystemStore = CertOpenSystemStore( 0, "CA")) { printf("The CA system store is open. Continue.\n"); } else { MyHandleError("The first system store did not open."); } //------------------------------------------------------------------- // Open a second store. // In order to work, a file-based certificate store named // teststor.sto must be available in the working directory. if(hFileStore = CertOpenStore( CERT_STORE_PROV_FILENAME, MY_ENCODING_TYPE, NULL, 0, L"testStor.sto" )) { printf("The file store is open. Continue.\n"); } else { MyHandleError("The file store did not open."); } //------------------------------------------------------------------- // Retrieve the first certificate from the Root store. // CertFindCertificateInStore could be used here to find // a certificate with a specific property. if(pCertContext=CertEnumCertificatesInStore( hSystemStore, pCertContext)) { printf("A certificate is available. Continue.\n"); } else { MyHandleError("No certificate available. " "The store may be empty."); } //------------------------------------------------------------------- // Find and print the name of the subject of the certificate // just retrieved. if(CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, 128)) { printf("Certificate for %s has been retrieved.\n", pszNameString); } else { printf("CertGetName failed. \n"); } //------------------------------------------------------------------- // Find out how much memory to allocate for the serialized element. if(CertSerializeCertificateStoreElement( pCertContext, // The existing certificate. 0, // Accept default for dwFlags, NULL, // NULL for the first function call. &cbElement)) // Address where the length of the // serialized element will be placed. { printf("The length of the serialized string is %d.\n", cbElement); } else { MyHandleError("Finding the length of the serialized " "element failed."); } //------------------------------------------------------------------- // Allocate memory for the serialized element. if(pbElement = (BYTE*)malloc(cbElement)) { printf("Memory has been allocated. Continue.\n"); } else { MyHandleError("The allocation of memory failed."); } //------------------------------------------------------------------- // Create the serialized element from a certificate context. if(CertSerializeCertificateStoreElement( pCertContext, // The certificate context source for the // serialized element. 0, // dwFlags. Accept the default. pbElement, // A pointer to where the new element will // be stored. &cbElement)) // The length of the serialized element, { printf("The encoded element has been serialized. \n"); } else { MyHandleError("The element could not be serialized."); } //------------------------------------------------------------------- // pbElement could be written to a file or be sent by email // to another user. // The following process uses the serialized // pbElement and its length, cbElement, to // add a new certificate to a store. if(CertAddSerializedElementToStore( hFileStore, // Store where certificate is to be added. pbElement, // The serialized element for another // certificate. cbElement, // The length of pbElement. CERT_STORE_ADD_REPLACE_EXISTING, // Flag to indicate what to do if a matching // certificate is already in the store. 0, // dwFlags. Accept the default. CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, NULL )) { printf("The new certificate is added to the second store.\n"); } else { MyHandleError("The new element was not added to a store."); } //------------------------------------------------------------------- // Next, another certificate will be retrieved from the system store // and its encoded part, pCertContext->pbCertEncoded, will be // used to create a new certificate to be added to the file store. if(pCertContext=CertEnumCertificatesInStore( hSystemStore, pCertContext)) { printf("Another certificate is available. Continue.\n"); } else { MyHandleError("No certificate is available. " "The store may be empty."); } //------------------------------------------------------------------- // Find and print the name of the subject of the certificate // just retrieved. if(CertGetNameString( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, 128)) { printf("Certificate for %s has been retrieved.\n", pszNameString); } else { printf("CertGetName failed. \n"); } //------------------------------------------------------------------- // Create a new certificate from the encoded portion of pCertContext // and add it to the file-based store. if(CertAddEncodedCertificateToStore( hFileStore, MY_ENCODING_TYPE, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL)) { printf("Another certificate is added to the file store.\n"); } else { MyHandleError("The new certificate was not added to the " "file store."); } //------------------------------------------------------------------- // Free memory. free(pbElement); CertCloseStore(hSystemStore,0); CertCloseStore(hFileStore,0); printf("The program ran without error to the end.\n"); } // End of main //------------------------------------------------------------------- // This example uses the function MyHandleError, a simple error // handling function, to print an error message to the standard // error (stderr) file and exit the program. // For most applications, replace this function with one // that does more extensive error reporting. void MyHandleError(char *s) { fprintf(stderr,"An error occurred in running the program. \n"); fprintf(stderr,"%s\n",s); fprintf(stderr, "Error number %x.\n", GetLastError()); fprintf(stderr, "Program terminating. \n"); exit(1); } // End of MyHandleError