SecureTime API Toolkit
Toolkit Home  

Example C Program: Time stamp a digital signature, Verify the time stamp

The program demonstrates time stamping a digital signature.  A hash is create from the digital signature.   The hash of the digital signature is then time stamped by the DigiStamp service using an Internet call.  The resulting time stamp token is decoded to extract the time stamp authorities time of signing.  The time stamp is then verified.

To execute this program you will need to have a private signing key installed in your key store.  To execute the time stamp verfiy you will need to retrieve the public key from the DigiStamp web site.

This example program illustrates the following tasks and combined use of the DigiStamp SecureTime API and MS CryptoAPI functions.

  • Several MS CrypoAPI functions create a demonstration signed message.
  • Initializing a DGS_TIMESTAMP_PARA   time-stamp service structure to be used in a call to DgsTimeStampRequest
  • Time stamp the signed message with DgsTimeStampRequest
  • Verify the time stamp using using DgsTimeStampVerify
//--------------------------------------------------------------------
// Example code for time stamping a digital signature.
//      Extending an example that is provided in MS Platform SDK,
//        "Signing, Encoding, Decoding and Verifying a Message"
//
//     The majority of this program is for creating the Signed Message
//     that will be time stamped.  This Signed Message would normally
//     be created through other processes in your system.


#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include "DgsTimeStamp.h"
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MAX_NAME 256

//--------------------------------------------------------------------
//   Define the name of a certificate subject.
//   To use this program, the definition of SIGNER_NAME
//   must be changed to the name of the subject of
//   a certificate that has access to a private key. 
//   That certificate must have either the CERT_KEY_PROV_INFO_PROP_ID,
//   or CERT_KEY_CONTEXT_PROP_ID property set for the context to 
//   provide access to the private signature key.

#define CERT_SUBJECT_NAME  L"RBorgers"

#define CERTIFICATE_STORE_NAME L"MY"

#define dgs_timestamp_servers1 "TSATEST1"
#define dgs_timestamp_servers2 "TSATEST2"
#define dgs_timestamp_servers3 "TSA1"

void main(int argc,char **argv)
{
        //--------------------------------------------------------------------
        // Declare and initialize variables. This includes getting a pointer 
        // to the message content. This sample program creates the message 
        // content and gets a pointer to it. In most situations, 
        // the content will exist somewhere and a pointer to it
        // will get passed to the application. 
        HCERTSTORE hSystemStoreHandle;     // System Certificate store handle.
        CRYPT_SIGN_MESSAGE_PARA   SignMessagePara;
        
        //--------------------------------------------------------------------
        //   The message to be signed and encoded.
        BYTE* pbContent = (BYTE*) "I've enjoyed a very challenging day.";
        
        //--------------------------------------------------------------------
        //   Local utility variables
        unsigned int loopCounter=0;
        //--------------------------------------------------------------------
        //   The length of the message. This must be one more than the value 
        //   returned by strlen() to include the terminal NULL character.
        DWORD cbContent = strlen((char *) pbContent)+1;
        
        //--------------------------------------------------------------------
        //    Arrays to hold the message to be signed and its length.
        const BYTE *rgpbToBeSigned[1] ;
        DWORD       rgcbToBeSigned[1];
        
        //--------------------------------------------------------------------
        //    The signer's certificate.
        PCCERT_CONTEXT pSignerCert; 
        
        //--------------------------------------------------------------------
        //   The length of the signed and encoded message.
        DWORD cbEncodedBlob;
        
        //--------------------------------------------------------------------
        //    Pointer that will hold the address of the buffer holding the
        //    signed and encoded message.
        BYTE *pbEncodedBlob = NULL;
        
        //--------------------------------------------------------------------
        //    Buffer to hold the name of the subject of a certificate.
        char pszNameString[MAX_NAME];
        
        //--------------------------------------------------------------------
        //  The following variables are used only in the time stamp phase.
        DWORD cbEncodedTSBlob;
        BYTE *pbEncodedTSBlob = NULL;
        LPSTR tsTime = NULL;
        DGS_TIMESTAMP_PARA   TimeStampPara;
        
        CRYPT_ALGORITHM_IDENTIFIER   AlgId;     // Data structure to hold the
        // hash algorithm identifier
        
        if(argc < 3){
        printf("DigiStampSampleProgram: Usage egMSClientSig <Account ID> <password>\n");
        printf("DigiStampSampleProgram: Exiting ......\n");
                exit(1);
        }
        
        //--------------------------------------------------------------------
        //  Begin processing. Display the original message.
        rgpbToBeSigned[0] = pbContent;
        rgcbToBeSigned[0] = cbContent;
        
        printf("DigiStampSampleProgram: The original message is: %s.\n",rgpbToBeSigned[0]);  
        
        
        //--------------------------------------------------------------------
        // Open a certificate store.
        if(hSystemStoreHandle = CertOpenStore(
                CERT_STORE_PROV_SYSTEM,
                0,
                0,
                CERT_SYSTEM_STORE_CURRENT_USER,
                CERTIFICATE_STORE_NAME)){
                printf("DigiStampSampleProgram: The cerrtificate store is open. \n");
        }
        else{
                DgsHandleError("Failed to open certificate repository");
        }
        
        //--------------------------------------------------------------------
        //  Find a certificate in the store. This certificate will
        //  be used to sign the message. The certificate must have a private 
        //  key accessible in order to sign the message.
        printf("DigiStampSampleProgram: Attempting to find certificate with 
                                        subject name: RBorgers .\n");
        if(pSignerCert = CertFindCertificateInStore(
                hSystemStoreHandle,
                MY_ENCODING_TYPE,
                0,
                CERT_FIND_SUBJECT_STR,
                CERT_SUBJECT_NAME,
                NULL)){
                
                //--------------------------------------------------------------------
                //   Get and print the name of the subject of the certificate.
                if(CertGetNameString(
                        pSignerCert,
                        CERT_NAME_SIMPLE_DISPLAY_TYPE ,
                        0,
                        NULL,
                        pszNameString,
                        MAX_NAME) > 1){
                        printf("DigiStampSampleProgram: The message 
                                                signer is %s .\n",pszNameString);
                }
                else{
                     DgsHandleError("Failed to get the name of the signer on the certificate");
                }
        }
        else{
            DgsHandleError("Failed to locate the certificate of the signer in the repository");
        }
        
        //--------------------------------------------------------------------
        // Initialize the CRYPT_SIGN_MESSAGE_PARA structure.
        // First, use memset to set all members to zero or NULL.
        // Then set the values of all members that must be non-zero.
        memset(&SignMessagePara, 0, sizeof(CRYPT_SIGN_MESSAGE_PARA));
        SignMessagePara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
        SignMessagePara.HashAlgorithm.pszObjId = szOID_RSA_MD2;
        SignMessagePara.pSigningCert = pSignerCert;
        SignMessagePara.dwMsgEncodingType = MY_ENCODING_TYPE;
        SignMessagePara.cMsgCert = 1;
        SignMessagePara.rgpMsgCert = &pSignerCert;
        
        //--------------------------------------------------------------------
        //  In two steps, sign and encode the message.
        //  First, get the number of bytes requred for the buffer
        //  to hold the signed and encoded message.
        if( CryptSignMessage(
                &SignMessagePara,
                FALSE,
                1,
                rgpbToBeSigned,
                rgcbToBeSigned,
                NULL,
                &cbEncodedBlob)){
                printf("DigiStampSampleProgram: The length needed for buffer to 
                                hold signed message is %d .\n",cbEncodedBlob);
        }
        else{
                DgsHandleError("Failed to get the length of encoded message");
        }
        
        //--------------------------------------------------------------------
        //   Allocate memory for the required buffer.
        if(!(pbEncodedBlob = (BYTE *)malloc(cbEncodedBlob)))
                DgsHandleError("Memory allocation failed.");
        
        //--------------------------------------------------------------------
        //   Call CryptSignMessage a second time to
        //   copy the signed and encoded message to the buffer.
        if( CryptSignMessage(
                &SignMessagePara,
                FALSE,
                1,
                rgpbToBeSigned,
                rgcbToBeSigned,
                pbEncodedBlob,
                &cbEncodedBlob)){
                printf("DigiStampSampleProgram: Successfully hashed and signed the 
                                                                        message.\n");
                printf("DigiStampSampleProgram: The hashed and signed 
                                                                message is:\n");
                for(loopCounter=0;loopCounter < cbEncodedBlob; loopCounter++)
                {
                        fprintf(stderr,"%#04X ",pbEncodedBlob[loopCounter]);
                }
        fprintf(stderr,"\n");
        }
        else{
                DgsHandleError("Failed to hash and sign the test message.\n");
        }
        
        //--------------------------------------------------------------------
        //  The previous code has been to create a signed message as input
        //  to the time stamp functions.
        
        
        //--------------------------------------------------------------------
        // Initialize the DGS_TIMESTAMP_PARA structure.
        // First, use memset to set all members to zero or NULL.
        // Then set the values of all members that must be non-zero.
        memset(&TimeStampPara, 0, sizeof(DGS_TIMESTAMP_PARA));
        TimeStampPara.cbSize = sizeof(DGS_TIMESTAMP_PARA);
        TimeStampPara.listOfServers[0] = dgs_timestamp_servers1;
        TimeStampPara.listOfServers[1] = dgs_timestamp_servers2;
        TimeStampPara.listOfServers[2] = dgs_timestamp_servers3;
        TimeStampPara.roundRobin=TRUE;
        TimeStampPara.retryNum=3;
        TimeStampPara.acctId=argv[1];
        TimeStampPara.password=argv[2];
        
        //--------------------------------------------------------------------
        //  Requesting the the time stamp be created for the SHA1 hash
        //     of my data.
        //  Initialize the CRYPT_ALGORITHM_IDENTIFIER data structure.
        AlgId.pszObjId=szOID_OIWSEC_sha1;
        AlgId.Parameters.cbData=0;
        
        //--------------------------------------------------------------------
        //  In two steps, create a time stamp for the signed message.
        //  First, get the number of bytes requred for the buffer
        //  to hold the time stamp.
        
        //  Ask for memory requirements
        if( DgsTimeStampRequest(
                &TimeStampPara,
                AlgId,    // time stamp is of sha1 hash of signature
                szOID_RSA_signedData, 
                        // content to be time stamped is signed message
                pbEncodedBlob,        // signed message
                cbEncodedBlob,
                0,                    // default, first signature in signer info
                25000,                 // nonce
                0,
                &cbEncodedTSBlob,
                NULL)){
                printf("DigiStampSampleProgram: The Time Stamp request 
                                        length is %d \n",cbEncodedTSBlob);
        }
        else{
                DgsHandleError("Faild to get the Time Stamp request length");
        }
        
        //--------------------------------------------------------------------
        //   Allocate memory for the required buffer.
        if(!(pbEncodedTSBlob = (BYTE *)malloc(cbEncodedTSBlob)))
                DgsHandleError("Failed to allocate memory for Time Stamp");
        
         //  We also want to see the value of "time of the time stamp" from 
        //         time stamp authority's clock.  Allocate memory.       
        if(!(tsTime = (BYTE *)malloc(20)))   // for time in GMT
                DgsHandleError("Failed to allocate memory for GMT time of 
                                                                Time Stamp");
        
        //--------------------------------------------------------------------
        //   Call DgsTimeStampRequest a second time to
        //   copy the encoded time stamp to the buffer.
        if( DgsTimeStampRequest(
                &TimeStampPara,
                AlgId,    // time stamp is of sha1 hash of signature
                szOID_RSA_signedData, 
                        // content to be time stamped is signed message
                pbEncodedBlob,        // signed message
                cbEncodedBlob,
                0,                    // default, first signature in signer info
                25000,                 // nonce
                pbEncodedTSBlob,
                &cbEncodedTSBlob,
                tsTime)){
                printf("DigiStampSampleProgram: Successfully created the Time 
                                        stamp at GMT time: %s \n",(LPSTR) tsTime);
                printf("DigiStampSampleProgram: The time stamp is:\n");
                for(loopCounter=0;loopCounter < cbEncodedTSBlob; loopCounter++)
                {
                        fprintf(stderr,"%#04X ",pbEncodedTSBlob[loopCounter]);
                }
        fprintf(stderr,"\n");
        }
        else{
                DgsHandleError("Failed to create Time stamp");
        }
        
        //--------------------------------------------------------------------
        // Verify the time stamp token
        if(DgsTimeStampVerify(
                oid_id_signatureTimeStampToken,
                pbEncodedBlob,        // signed message that was time stamped
                cbEncodedBlob,
                0,                 // default, first signature in signer info 
                pbEncodedTSBlob,
                &cbEncodedTSBlob,
                hSystemStoreHandle,   // handle to the certificate store
                tsTime)){
                printf("DigiStampSampleProgram: Verification of time stamp 
                  succeeded. The time stamp GMT time is %s .\n",(LPSTR) tsTime);
        }
        else{
                DgsHandleError("Failed to verify the Time stamp");
        }
        
        //--------------------------------------------------------------------
        // Clean up.
        if (pbEncodedTSBlob)
                free(pbEncodedTSBlob);
        if (pbEncodedBlob)
                free(pbEncodedBlob);
        if (tsTime)
                free(tsTime);
        if(pSignerCert)
                CertFreeCertificateContext(pSignerCert);
        if(hSystemStoreHandle)
                CertCloseStore(hSystemStoreHandle,CERT_CLOSE_STORE_FORCE_FLAG);
        
        printf("DigiStampSampleProgram: The sample program completed successfully.\n");
} //  End of main

Home

  Feedback      Related Links   Contact Us   Mailing List    Privacy Statement
Copyright 2000-2005 DigiStamp, Inc.
All Rights Reserved
SecureTime, IPVault, IPProtector, and e-TimeStamp  are service marks of the DigiStamp, Inc.