Legal Information

Microsoft CryptoAPI

Information in this document is subject to change without notice. The names of companies, products, people, characters, and/or data mentioned herein are fictitious and are in no way intended to represent any real individual, company, product, or event, unless otherwise noted. Complying with all applicable copyright laws is the responsibility of the user. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, for any purpose, without the express written permission of Microsoft Corporation. If, however, your only means of access is electronic, permission to print one copy is hereby granted.

Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property.

© 1998 Microsoft Corporation. All rights reserved.

Microsoft, Windows, Win32, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries.

Other product and company names mentioned herein may be the trademarks of their respective owners.


Introduction

The Microsoft® Cryptographic Application Programming Interface (CryptoAPI) provides services that enable application developers to add authentication, encoding, and encryption to their Microsoft Win32®-based applications. Application developers can use the functions in the CryptoAPI without knowing anything about the underlying implementation, in much the same way as they can use a graphics library without knowing anything about the particular graphics hardware configuration.


Audience

This document is intended to be used by developers familiar with the Microsoft Windows® programming environment. Although not required, a good understanding of the basics of cryptography or other security-related subjects is advised. For recommended reading, see Related Documentation.


CryptoAPI Tasks

  • Authenticating Network Users
  • Introduction to CSPs
  • Encoding and Decoding Network Messages
  • Encrypting and Decrypting Data
  • Learning About CryptoAPI
  • Learning About Cryptography
  • Signing and Verifying Data


What's New in the CryptoAPI Version 2.0

CryptoAPI version 1.0 contained all the necessary functionality to handle straight cryptography. In this document, the original version 1.0 functionality is now called Cryptographic Functions. However, there is a rapidly evolving trend toward the incorporation of certificates in secure communications. Cryptography provides two of the three most important aspects of secure communications—privacy and integrity. The other important aspect is authentication—the certification that both the sender and recipient are who they say they are. The method that is being used to provide authentication in secure communications is digital certificates (often shortened to just certificates).

The CryptoAPI version 2.0 has all the same functionality contained in version 1.0, plus it adds all the necessary functionality to manage and use certificates in secure communications, and functions to encode and decode PKCS #7 messages.

The certificate management API includes functions to maintain and manage a persistent storage of certificates (called a certificate store), and a set of functions that provide for the incorporation of certificates in outgoing messages and the verification of certificates that are being received in messages.

The message management API is provided at two levels—low-level message functions and simplified message functions. The low-level message functions provide more flexibility than the simplified message functions, but require more function calls.

In September 1996, Microsoft® hosted a Security Design Review conference attended by several hundred interested developers. The purpose of this design review was to present the CryptoAPI as it existed at that point, so that feedback could be received about its usefulness and any change in direction that was needed. As a result of that feedback and due to ongoing development efforts, significant changes have occurred to the CryptoAPI since the conference. The changes that have occurred since the conference are presented in The Microsoft CryptoAPI Summary of Changes.


Related Documentation

Additional documents that will help you understand cryptography and authentication, and the associated security issues include:

  • Schneier, Bruce. Applied Cryptography. John Wiley & Sons, 1996.
  • Stinson, D. R. Cryptography: Theory and Practice. CRC Press, 1995.
  • Anderson, R. Why Cryptosystems Fail. Communications of the ACM, v. 37, n. 11, November 1994, pp. 32-40.
  • Cormen, Thomas H., Charles E. Leiserson, Ronald L. Rivest. Introduction to Algorithms. MIT Press, 1990.
  • Davies, D.W. and W.L. Price. Security for Computer Networks. John Wiley & Sons, 1989.
  • Denning, Dorothy E. Cryptography and Data Security. Addison-Wesley, 1982.
  • International Standard ISO/IEC 9594-8, Second Edition, Information Technology—Open Systems Interconnection—The Directory: Authentication Framework.
  • RSA Laboratories, a division of RSA Data Security, Inc., RSA Data Security, Inc. Public-Key Cryptography Standards (PKCS), Copyright© 1991–1993.


Overview of the Microsoft CryptoAPI

Secure communication over nonsecure networks generally involves two major areas of concern: privacy and authentication.

For greater privacy, users sometimes need to prevent anyone except the intended recipient from being able to read a message. Ensuring privacy usually involves some form of a process known as cryptography, which is discussed in the following section.

Authentication is the need to know that the entity with whom you are communicating is, in fact, who it claims to be. Perhaps the most common method of accomplishing authentication is through the use of certificates. A certificate is a set of data that identifies an entity, contains that entity's public key (a cryptographic key) and is issued by a trusted organization or entity called a Certification Authority (CA) only after a CA has verified that the entity is who it says it is. The communication between the CA and the certificate requester could be accomplished by the requester physically carrying the necessary information, stored on a floppy disk, to the CA. However, the communication is usually accomplished with a signed message sent over a network. The CA often uses a trusted application program called a certificate server.


Cryptography

Cryptography is the process of encrypting (scrambling) messages such that the messages can be stored and transmitted securely. This section introduces the basic terminology of cryptography and explains some of the common methods used.

Cryptography can be used to achieve secure communication, even when the transmission media (for example, the Internet) is untrustworthy. You can also use cryptography to encrypt your sensitive files, so that an intruder cannot understand them.

Cryptography can be used to ensure data integrity, as well as to maintain secrecy.

Using cryptography, it becomes possible to verify the origin of data and messages with digital signatures. For further details see Hashes and Digital Signatures.

When using cryptographic methods, only the session and private cryptographic keys must remain secret. The algorithms, the key sizes, and file formats can be made public without compromising security.


Data Encryption

Using data encryption, a plaintext message can be scrambled so that it appears like random gibberish and is very difficult to transform back to the original message without a secret key. This message can consist of ASCII text, a database file, or any data you want to store or transmit securely. In this document, the term message is used to refer to any piece of data, plaintext is used to refer to data that has not been encrypted, and ciphertext refers to data that has.


Encryption/Decryption Process

Once a message has been encrypted, it can be stored on nonsecure media or transmitted over a nonsecure network and still remain secret. Later, the message can be decrypted into its original form. This process is shown in the following illustration.

Data encryption and decryption is a simple process. When a message is encrypted, an encryption key is used. This is comparable to a key that is used to lock a padlock. To decrypt the message, a decryption key must be used. The encryption and decryption keys are often, but not always, the same key.

It is very important to keep the keys safe and transmit them securely to other users. This is discussed further in Encrypting and Decrypting Data. However, the challenge is to properly restrict access to the decryption key, because anyone who possesses it will be able to decrypt all messages that were encrypted with the corresponding encryption key.


Symmetric Versus Public-Key Encryption

There are two main classes of encryption algorithms: symmetric algorithms and public-key algorithms (also known as asymmetric algorithms). Systems that use symmetric algorithms are sometimes referred to as conventional.

Symmetric Algorithms

Symmetric algorithms are the most common type of encryption algorithm. They are known as symmetric because the same key is used for both encryption and decryption. Unlike the keys used with public-key algorithms, symmetric keys are frequently changed. For this reason, they are referred to here as session keys.

Compared to public-key algorithms, symmetric algorithms are very fast and, thus, are preferred when encrypting large amounts of data. Some of the more common symmetric algorithms are RC2, RC4, and the Data Encryption Standard (DES).

Public-Key Algorithms

Public-key (asymmetric) algorithms use two different keys: the public key and the private key. The private key is kept private to the owner of the key pair, and the public key can be distributed to anyone who requests it (often by means of a certificate). If one key is used to encrypt a message, then the other key is required to decrypt the message.

Public-key algorithms are very slow — on the order of 1,000 times slower than symmetric algorithms. Consequently, they are typically used only to encrypt session keys. They are also used to digitally sign messages, as discussed in the next section.

One of the most common public-key algorithms is the RSA Public-Key Cipher.


Digital Signatures

You can use digital signatures to distribute a message in plaintext form, when you want the recipients to be able to verify that the message comes from you and that it hasn't been tampered with. Signing a message does not alter the message, it simply generates a digital signature string you can either bundle with the message or transmit separately.


Signature Generation/Validation Process

Digital signatures are generated by using public-key signature algorithms. Use a private key to generate the signature, and use the corresponding public key to validate the signature. This process is shown in the following illustration.


Authentication

As mentioned in the introduction of this section, authentication involves the process of verifying the identity of the person or entity with whom you are communicating. Certificates are a common way to achieve authentication.

A certificate is a set of data that identifies an entity, contains that entity's public key (a cryptographic key), and is issued by a trusted organization or entity called a Certification Authority (CA) only after the CA has verified that the entity is who it says it is. The data set includes the entity's public cryptographic key. When the sender of a message signs the message with its private key (and sends a copy of its certificate with the message), the recipient of the message can use the sender's public key (retrieved from the certificate) to verify that the sender is who it says it is.

On a network, there is often a trusted application, managed by a CA and running on a secure computer, that is known as a certificate server. Such an application has access to the public key of each user. Certificate servers dispense messages known as certificates, each of which contains the public key of one of its client users. Each certificate is signed with the private key of the Certification Authority.

Additional information on authentication through the use of certificates is presented in Authentication Using Certificates.


The CryptoAPI Programming Model

The Microsoft CryptoAPI Programming Model

The Microsoft® CryptoAPI provides privacy through the use of simplified message functions, low-level message functions, and base cryptographic functions. These functions provide a way for applications to encrypt or digitally sign data in a flexible manner, while providing protection for the user's sensitive private-key data.

Authentication through the use of certificates is supported in the CryptoAPI by certificate encode/decode functions, and certificate store functions. A certificate is a data set that uniquely describes a particular entity, and usually incorporates that entity's public key. A certificate is issued by a Certification Authority (CA), after it has determined the authenticity of the entity. More detailed information about public keys and certificates is provided in Generating Cryptographic Keys, and Authentication Using Certificates.

The CryptoAPI programming model can be compared to the Windows GDI model in that Cryptographic Service Providers (CSP) are analogous to graphics device drivers, and the cryptographic hardware (optional) is analogous to graphics hardware. Just as well-behaved applications are not allowed to communicate directly with graphics device drivers and hardware, well-behaved applications cannot directly access the CSPs and cryptographic hardware.


System Architecture

The CryptoAPI system architecture is composed of five different major functional areas, as shown in the following illustration. The functional areas are: certificate encode/decode functions, certificate store functions, base cryptographic functions, low-level message functions, and simplified message functions.

Except for the base cryptographic functions, the names of the functions contained in each of the functional areas have a key word in their name indicating the functional area. Those key words are described as follows:

  • There are two general purpose functions in the certificate encode/decode functional area: CryptDecodeObject and CryptEncodeObject.
  • Certificate store function names contain the word "Store."
  • Low-level message function names contain the word "Msg."
  • Simplified message function names contain the word "Message."
  • All of the remaining functions are the base cryptographic functions.

An application can communicate with any of these functional areas through the functions contained therein. These functions, when taken in total, make up the CryptoAPI. The base cryptographic functions, in turn, rely upon the CSPs to provide the necessary cryptographic algorithms and to provide secure storage for any cryptographic session or public or private keys that may be generated.

Notice that, although an application can communicate directly with any of the five functional areas, it cannot communicate directly with a CSP. All application-to-CSP communications must occur through the base cryptographic functions exposed in the CryptoAPI. Each base cryptographic function that communicates with a CSP has a parameter that specifies which CSP to use.


The Certificate Encode/Decode Functions

These functions manage the encoding and decoding of certificates and related material for use over an Open Systems Interconnect (OSI) network (as described in the CCITT X.200 recommendation). OSI is an internationally standardized architecture that governs the interconnection of computers from the physical layer up to the application layer. The OSI method of specifying abstract objects (data) is called Abstract Syntax Notation One (ASN.1) encoding and decoding (as defined in CCITT X.209). Additional information on encoding and decoding is presented in Certificate Encoding/Decoding.


The Certificate Store Functions

Certificate store functions provide for certificate storage, retrieval, and manipulation. A user site may, over a period of time, collect many, many certificates. Typically, the site will have a few certificates describing the user of the site, and then many certificates describing entities with which the user wishes to communicate. Usually, for each entity there is more than one certificate—there is a complete chain of certificates that provides a verification trail back to the root CA.

The certificate store functions provide a way to store, retrieve, enumerate, verify, and use the information stored in the certificates.


The Base Cryptographic Functions

These are the functions that provide you with the most flexibility in applying cryptography to your applications. It is through these functions that communication with the CSPs occurs.

All cryptographic operations are performed by independent modules known as Cryptographic Service Providers (CSP). A minimum of one CSP is required, but more than one can exist. If more than one exists, the one to use can be specified in the CryptoAPI cryptographic function calls. One CSP, the Microsoft Base Cryptographic Provider, is bundled with the CryptoAPI.

Each CSP provides a different implementation of the cryptographic support provided to the CryptoAPI. Some provide stronger cryptographic algorithms, while others contain hardware components such as smart cards. In addition, some CSPs may occasionally communicate with users directly, such as when digital signatures are performed by using the user's signature private key.


The Low-Level Message Functions

These functions provide the capability to quickly create PKCS#7 messages. These functions provide the necessary functionality to encode data for transmission and decode data that has been received. Functionality is also provided to decrypt and verify the signatures of received messages. For an overview of the PKCS#7 standard and the low-level message functions, see Using Low Level Message Functions.


The Simplified Message Functions

These functions are at a higher level than the low-level message functions and, in fact, wrap several of the low-level message functions and certificate functions into a single function that performs a specific task in a specific manner. These functions reduce the number of function calls that must be used to accomplish a task, thereby enabling quicker use of the CryptoAPI. For an overview of how to use these functions, see Using Simplified Message Functions.


Cryptographic Service Providers (CSP)

Cryptographic Service Providers, CSPs, are independent modules that perform the real cryptographic work. Ideally, they are written to be completely independent of any particular application, so that any given application will run with a variety of CSPs. In reality however, some applications may have very specific requirements that require a custom CSP.

A CSP consists of, at a minimum, a dynamic-link library (DLL) and a signature file. The signature file is necessary to ensure that the CryptoAPI recognizes the CSP. The CryptoAPI validates this signature periodically to ensure that the CSP has not been tampered with.

Some CSPs may implement a fraction of their functionality either in an address-separated service called through local RPC, or in hardware called through a system device driver. Isolating global key-state and central cryptographic operations in hardware or in a service keeps keys and operations safe from tampering within the application data space.

Applications should not take advantage of attributes particular to a specific CSP. For example, the Microsoft Base Cryptographic Provider (supplied with the CryptoAPI) currently uses 40-bit session keys and 512-bit public keys. When applications manipulate these, they should be careful not to make assumptions about the amount of memory needed to store them. Otherwise, the application is likely to fail when the user loads a different CSP onto the system. You should take care to write applications that are as well-behaved and as flexible as possible.


Key Databases

Each CSP has a key database in which it stores its persistent cryptographic keys. Each key database contains one or more key containers, each of which contains all the key pairs belonging to a specific user (or CryptoAPI client). Each key container is given a unique name, which applications provide to the CryptAcquireContext function when acquiring a handle to the key container. The following is an illustration of the contents of a key database.

The CSP stores each key container from session to session, including all the public/private key pairs it contains. However, session keys are not preserved from session to session.

Generally, a default key container is created for each user. This key container takes the user's logon name as its own name, which is then used by any number of applications. It is also possible for an application to create its own key container (and key pairs), which it usually names after itself.


Session Keys

Session keys are used when encrypting and decrypting data. They are created by applications using either the CryptGenKey or the CryptDeriveKey function. These keys are kept internal to the CSP for safekeeping.

Unlike public/private key pairs, session keys are volatile. Applications can save these keys for later use or transmission to other users by using the CryptExportKey function to export them from the CSP into application space in the form of an encrypted "key blob." (This procedure is discussed in Exchanging Cryptographic Keys.)


Public/Private Key Pairs

Each user generally has two public/private key pairs. One key pair is used to encrypt session keys and the other to create digital signatures. These are known as the key exchange key pair and the signature key pair, respectively. These key pairs are discussed in Generating Cryptographic Keys.

Note that, while key containers created by most CSPs will contain two key pairs, this is not required. Some CSPs do not store any key pairs, while others store additional ones. For more details, see Interfacing with a Cryptographic Service Provider (CSP).


Using the CryptoAPI in your Applications

Each of the five functional areas contains functions that fall into different task-oriented categories. The following list explains the functional areas.

  • Certificate encode/decode functional area. The functions in this functional area fall into the single category of encoding and decoding certificates and related data. (See Certificate Encoding/Decoding and CryptEncodeObject/CryptDecodeObject Functions.)
  • Certificate Store functional area. All of these functions fall into the single category of certificate management. (See Authentication Using Certificates, Managing Certificates, and Certificate Store Functions.)
  • Base cryptography functional area. This area includes the following types of functions:
    • Context functions. These functions are used by applications to connect to a CSP. These functions enable applications to choose a specific CSP by name, or get one with a needed class of functionality. (See Interfacing with a Cryptographic Service Provider (CSP), and Cryptographic Functions.)
    • Key generation functions. These functions are used by applications to generate and customize cryptographic keys. Full support is included for changing chaining modes, initialization vectors, and other encryption features. (See Generating Cryptographic Keys, and Cryptographic Functions.)
    • Key exchange functions. These functions are used by applications to exchange or transmit keys. These functions can also be used to implement fully authenticated three-leg key exchanges. (See Exchanging Cryptographic Keys, and Cryptographic Functions.)
    • Data encryption functions. These functions are used by applications to encrypt or decrypt data. Support is also included for simultaneously encrypting and hashing data. (See Encrypting and Decrypting Data, and Cryptographic Functions).
    • Hashing and signature functions. These functions are used by applications to compute cryptographically secure data hashes and to digital sign data. (See Hashes and Digital Signatures, and Cryptographic Functions).

Note Throughout this document, except for instances relating directly to messages, the term hash or hashing will be used rather than digest or digesting. In most cases, the terms could be used interchangeably.

  • The low-level message functional area. This area includes all the low-level message functions. They provide more flexibility than the simplified message functions, but usually require more function calls. (See Using Low-Level Message Functions, and Low-Level Message Functions).
  • The simplified message functional area. This area includes the following types of functions:
    • Encryption and decryption functions. These functions are used to encode and encrypt, and decode and decrypt messages and data. (See Using Simplified Message Functions, and Simplified Message Functions).
    • Message signing functions. These functions are used to sign messages and data. (See Using Simplified Message Functions, and Simplified Message Functions.)
    • Signature and data verification functions. These functions are used both to sign out-going messages and to verify the authenticity of signatures that have been applied to received messages and related data. (See Using Simplified Message Functions, and Simplified Message Functions.)


Interfacing with a Cryptographic Service Provider (CSP)

The Cryptographic Service Provider (CSP) architecture provides a safe way for multiple applications to access cryptographic and signature services. Instead of being passive sets of encryption routines, CSPs are independently functioning cryptographic modules capable of authenticating the user and checking for user assent to actions.

For example, some CSPs will require a personal identification number (PIN) to be entered by a user before a digital signature is generated, while some require a smart card. Others may require user intervention before executing private key functions, and still others have no authentication at all. The quality of protection for keys within the system is a design parameter of the CSP itself and not the system as a whole. This lets the same applications run in a variety of security contexts without modification.

The amount of access that applications have to the cryptographic internals has been carefully restricted. This facilitates secure and portable application development. The following three design rules apply:

  • Applications cannot directly access keying material. Because all keying material is generated within the CSP and used by the application through opaque handles, there is no risk of an application or its associated DLLs either divulging keying material or choosing keying material from poor random sources.
  • Applications cannot specify the details of cryptographic operations. The CSP interface only allows applications to specify broad actions to take (for example, encrypt data by using algorithm X and sign data). The actual implementation of the cryptographic operations is the responsibility of the CSP. This limits the scope of the API because esoteric protocols require application intervention, but make a basic set of operations readily available to all applications.
  • Applications do not handle user authentication data. User authentication is done by the CSP. In this way, CSPs that have better authentication capabilities (for example, biometric inputs and data keys) will function without needing to change the application authentication model. It also prevents applications from divulging user secrets.


Different Types of CSPs

Each provider has both a name and a type. For example, the name of the CSP currently shipped with the operating system is Microsoft® Base Cryptographic Provider version 1.0, and its type is PROV_RSA_FULL. The name of each provider is unique; the provider type is not.


Provider Types

The field of cryptography is very large. There are dozens of different standard data formats and protocols. These are generally organized into groups or families, each of which has its own set of data formats and way of doing things. Even if they use the same algorithm (for example, the RC2 block cipher), two families will often use a different padding scheme, different key lengths, and different default modes. The CryptoAPI has been designed so that each CSP type represents a particular family.

When an application connects to a CSP of a particular type, each of the CryptoAPI functions will, by default, operate in a way prescribed by the family that corresponds to the CSP type. An application's choice of provider type specifies the following items:

  • Key exchange algorithm. Each provider type specifies one and only one key exchange algorithm. Every CSP of a particular type must implement this algorithm. The only way applications can specify which key exchange algorithm is used is by selecting a CSP of the appropriate provider type.
  • Digital signature algorithm. This is the same as with the key exchange algorithm. Each provider type specifies one and only one digital signature algorithm.
  • Key blob format. When a public key or session key is exported out of a CSP, the format of the resulting key blob is specified by the provider type.
  • Digital signature format. The provider type prescribes a particular digital signature format. This ensures that a signature produced by a CSP of a given provider type can be verified by any CSP of the same provider type.
  • Session key derivation scheme. When a key is derived from a hash, the method used is specified by the provider type.
  • Key length. Some provider types will specify that the public/private key pairs or the session keys be of a certain length.
  • Default modes. The provider type will often specify a default mode for various options, such as the block encryption cipher mode or the block encryption padding method.

Each application will generally work only with a single type of CSP. However, an advanced application might connect to more than one CSP at a time. When writing an application, you will often need to obtain all the documentation that relates to the CSP type you are using. For example, it is not recommended that you try to write an application by using the PROV_RSA_FULL provider type without obtaining the Public-Key Cryptographic Standards (PKCS) from RSA Data Security, Inc. The relevant third-party documentation for each provider type is listed later in this chapter.


Predefined Provider Types

A number of provider types have already been defined. The following table lists these provider types, along with the algorithms that each type must support. A CSP of a given type is free to support other algorithms in addition to the ones listed.

Provider Type | Key Exchange | Signature | Encryption | Hashing
PROV_RSA_FULL | RSA | RSA | RC2, RC4 | MD5, SHA
PROV_RSA_SIG | n/a | RSA | n/a | MD5, SHA
PROV_DSS | n/a | DSS | N/A | MD5, SHA
PROV_DSS_DH | DH | DSS | DES40 | MD5, SHA
PROV_DH_SCHANNEL | DH | DSS | RC2, RC4, DES40 | MD5, SHA
PROV_FORTEZZA | KEA | DSS | Skipjack | SHA
PROV_MS_EXCHANGE | RSA | RSA | CAST | MD5
PROV_RSA_SCHANNEL | RSA | RSA | RC2, RC4, DES40 | MD5, SHA
PROV_SSL | RSA | RSA | varies | varies

If two or more applications plan to exchange keys and encrypted messages, they should both use CSPs of the same type; however, some CSP types may be partially compatible with others.

Anyone writing a custom CSP can define a new provider type. However, this person is then responsible for distributing the new provider type to the authors of any applications that are to use it.

In the event that the previous table mentioned algorithms you are not familiar with, the following table provides a brief description of each.

Algorithm | Description
CAST | This is a 64-bit symmetric block cipher developed by C. M. Adams and S. E. Tavares. This algorithm is somewhat similar to DES (Data Encryption Standard).
DES | National Institute of Standards and Technology (NIST) Data Encryption Standard. This is a 64-bit symmetric block cipher that has a fixed key length of 56 bits.
DH | Diffie-Hellman. This is a public-key algorithm used for secure key exchange. It cannot be used for data encryption.
DSS | Digital Signature Standard. This standard uses the Digital Signature Algorithm (DSA), which is a public-key cipher used to generate digital signatures. It cannot be used for data encryption.
KEA | Key Exchange Algorithm. This is an improved version of Diffie-Hellman.
MD2 | A hashing algorithm that produces a 128-bit hash value.
MD4 | A hashing algorithm that produces a 128-bit hash value.
MD5 | An improved version of MD4. It also produces a 128-bit hash value.
RC2 | RC2 Block Cipher. This is a 64-bit symmetric block cipher.
RC4 | RC4 Stream Cipher. This is a symmetric stream cipher.
RSA | RSA Public-Key Cipher. This is a popular public-key cipher used for both encryption and signatures.
SHA | Secure Hash Algorithm. This is a hashing algorithm that produces a 160-bit hash value.
Skipjack | This is the algorithm used by the Clipper and Capstone chips. It is a symmetric block cipher with a fixed key length of 80 bits.


PROV_RSA_FULL Provider Type

This provider type supports both digital signatures and data encryption, and is considered general purpose. The RSA public-key algorithm is used for all public-key operations.

This provider type has been thoroughly defined by Microsoft® and RSA Data Security. It is described in the following documents:

  • Microsoft Cryptographic Service Provider Programmer's Guide, Microsoft, 1996.
  • RSA Laboratories, Public-Key Cryptography Standards, RSA Data Security, November 1993.


PROV_RSA_SIG Provider Type

This provider type is a subset of PROV_RSA_FULL. Only those functions and algorithms required for hashes and digital signatures are supported.


PROV_DSS Provider Type

This provider type is similar to PROV_RSA_SIG in that it only supports hashes and digital signatures, but the signature algorithm specified by the PROV_DSS provider type is the Digital Signature Algorithm (DSA).

The DSA was proposed by the National Institute of Standards and Technology (NIST). A description of the algorithm can be found in many books on cryptography or from the following government reference:

  • "Proposed Federal Information Processing Standard for Digital Signature Standard (DSS)," Federal Register, v. 57, no. 21, 31 Jan 1992, pp. 3747-3749.


PROV_DSS_DH Provider Type

This provider is a superset of the PROV_DSS provider type. It contains the same signature algorithms as PROV_DSS, plus it includes the DIFFIE-HELLMAN key exchange algorithms.


PROV_FORTEZZA Provider Type

The set of cryptographic protocols and algorithms known as Fortezza is owned by the National Institute of Standards and Technology (NIST). More information is available directly from them.


PROV_MS_EXCHANGE Provider Type

CSPs of this type are designed to cater to the cryptographic needs of the Microsoft Exchange mail application, as well as other applications that are compatible with Microsoft Mail. This provider type is preliminary.


PROV_SSL Provider Type

CSPs of this type support the Secure Sockets Layer (SSL) protocol. A specification explaining the SSL protocol is available from Netscape Communications Corp.


Microsoft Providers

For information on the CSPs provided by Microsoft, see Microsoft Cryptographic Service Providers.


Connecting to a Cryptographic Service Provider

Each time an application is run, the first Microsoft CryptoAPI function an application calls is the CryptAcquireContext function. This function returns to the application a handle to a particular CSP. In addition, this handle specifies a particular key container within the CSP, either a specific container that you ask for, or the default for the currently logged on user. If the CSP has just been installed and no key containers yet exist, the CryptAcquireContext function can also be used to create a new one.

When an application uses CryptAcquireContext to obtain a CSP handle, it specifies a provider type and, optionally, a provider name. If both a type and a name are specified, then the function looks for a CSP with precisely the same type and name, loads it into memory, and returns a handle to the application.

When an application calls CryptAcquireContext and specifies a provider type but no provider name, the function tries to find the provider name, first on a list of default providers associated with the logged-on user and, if that fails, from a list of default providers associated with the computer.

After the provider name has been determined successfully, the CryptAcquireContext function searches for the CSP, loads it into memory, and returns a handle to the application.


Service Provider Functions Summary

The functions described in this section are used by applications to connect to and disconnect from CSPs. The following table briefly describes each function.

Function | Description
CryptAcquireContext | Acquires a handle to the current user's key container within a particular CSP.
CryptGetProvParam | Retrieves attributes of a CSP.
CryptReleaseContext | Releases the handle acquired by CryptAcquireContext.
CryptSetProvider | Specifies the user default CSP for a particular CSP type.
CryptSetProvParam | Specifies attributes of a CSP.


Generating Cryptographic Keys

Keys lie near the center of almost every cryptographic operation. It is important to keep these secret because whoever possesses a given key then has access to any data that key is associated with. For example, if a key is used to encrypt a file, then anyone with a copy of that key can easily decrypt the file. Furthermore, if the key is used to sign messages, then anyone possessing that key can forge the signatures.


Cryptographic Key Overview

There are two types of cryptographic keys: session keys and public/private key pairs.

Session Keys. Session keys are used primarily for data encryption/decryption and are used with symmetric encryption algorithms. That is, the same key is used for both encryption and decryption.

Most of the activity involving session keys relates to keeping them secret. It is important to keep the number of people who possess a particular session key as small as possible (one or two people is recommended).

Public/Private Key Pairs. Key pairs are composed of two components: the public key and the private key. The public key is made available (via an Internet server, e-mail, or some other means) to whomever needs or wants it, while the private key, on the other hand, is kept secret. Only the owner of the key pair is allowed to possess the private key.

If one of the keys (the public key) is used to encrypt a message, then the other key is required to decrypt it. Thus, if you want to send someone a message, you can encrypt the file by using their public key and be confident that no one else will be able to read the file.

If the private key is used to sign a message, then the other key must be used to validate the signature. For example, if you want to send someone a digitally signed message, you would sign the message with your private key, and the other person could verify your signature by using your public key.

Unfortunately, public-key algorithms are very slow and it is impractical to use them to encrypt large amounts of data. In practice, symmetric algorithms are used for encryption/decryption, while the public-key algorithms are used merely to encrypt the session keys. Similarly, it is not practical to use public-key signature algorithms to sign large messages. Instead, a hash is made of the message and the hash value is signed. For more details on hashing and signatures, see Hashes and Digital Signatures.


Using Keys With CryptoAPI

Using Keys With the Microsoft CryptoAPI

All keys in the Microsoft® CryptoAPI are stored within cryptographic service providers (CSP). CSPs are also responsible for creating the keys, destroying them, and using them to perform a variety of cryptographic operations. Exporting keys out of the CSP so that they can be sent to other users is discussed in Exchanging Cryptographic Keys.


Using Session Keys

Applications can create any number of session keys, which can be used to encrypt messages. However, these keys are not preserved by the CSP from session to session. If you want to use a key for long periods, you need to export the key out of the CSP and into your application for long-term storage. The procedure for doing this is discussed in Exchanging Cryptographic Keys.

Session keys are created by using either the CryptGenKey function or the CryptDeriveKey function. When these keys are generated, it is necessary to specify the algorithm to use for any subsequent encryption/decryption operations. This algorithm must be one of the symmetric algorithms supported by the CSP being used.


Using Public/Private Key Pairs

For each user, the CSP usually maintains two public/private key pairs. These keys are maintained from session to session.

The key exchange key pair (also known as the exchange key) is used to encrypt session keys so that they can be safely stored and exchanged with other users. This is discussed in detail in Exchanging Cryptographic Keys.

The digital signature key pair (also known as the signature key) is used to sign hashes of data. This is discussed in detail in Hashes and Digital Signatures.

There are a number of reasons for having two separate key pairs. For example, some CSP developers may opt to use one algorithm for key exchange and another for digital signatures. This is because some digital signature algorithms are unsuitable for encryption or key exchange, and vice versa. Also, if some data (for example, a session key) is both signed and encrypted with the same key pair, subtle weaknesses could be introduced that make the data vulnerable.

The exchange key and the signature key pairs are created by calling the CryptGenKey function and specifying either AT_KEYEXCHANGE or AT_SIGNATURE. The CSP implements these keys in an application-independent manner. Applications do not have access to the details about the algorithm used.


Summary of Key Generation Functions

The functions described in this section are used by applications to create, configure, and destroy cryptographic keys, and to exchange them with other users. The following table briefly describes each function.

Function | Description
CryptDeriveKey | Create a key derived from a password.
CryptGenKey | Create a random key.


Exchanging Cryptographic Keys

This chapter discusses those situations where you must export keys from the secure environment of the cryptographic service provider (CSP) and into your application's data space. Keys that have been exported are stored in encrypted data structures known as key blobs. These are discussed in Key Blobs Explained.

There are two specific situations where it is necessary to export keys:

  • You want to save a session key for later use by your application. For example, if your application has just encrypted a database file and you want your application to decrypt this file at a later time, your application is responsible for storing the encryption key. This is necessary because CSPs do not preserve symmetric keys from session to session.
  • You want to send a key to someone else. This would be much easier (for your application) if the respective CSPs could communicate directly, but they cannot. This means the key has to be exported from your CSP, transmitted by your application to the destination application, and then imported into the destination CSP. If you don't trust the communication path, this can become somewhat complicated. However, this is covered in the next few sections.

Note This chapter assumes that users (or Microsoft® CryptoAPI clients) already possess their own set of public/private key pairs. Instructions for creating these can be found in Generating Cryptographic Keys.


Storing Session Keys

This section discusses how you use the CryptoAPI to store a session key for later use. This is useful in those situations where you have encrypted a file and want to decrypt the file at a later time. Another possible situation is one in which you have shared the session key with another user and you want to use the key at a later time to send the other user encrypted messages.

In either case, your application will have to store the session key outside of the CSP for a certain period. Following is the procedure for storing a session key.

To store a session key
  1. Create a simple key blob by using the CryptExportKey function. This will transfer the session key from the CSP to your application's memory space. Specify that your own key exchange public key be used to sign the key blob.
  2. Store the signed key blob to disk. The assumption is made here that all disks are nonsecure.
  3. Later, when you need to use the key, read the key blob from disk.
  4. Import the key blob back into the CSP by using the CryptImportKey function.

If the session key is to be bundled with an encrypted file only (so that you can later decrypt the file), and the key is not going to be used to encrypt any more data, then the preceding procedure provides adequate security.

If you plan to use the session key for encryption at a later time, then the key blob should be signed with your key exchange private key before the key blob is stored to disk. When you later read the key blob back from disk, you should validate the signature to make sure the key blob is intact. If these steps are omitted, then someone with access to your storage media can create a new session key, encrypt it with your key exchange public key, and substitute it for your key blob. You could then unknowingly use the substituted session key to encrypt files and messages, which the unscrupulous user could then easily decrypt. Digital signatures are discussed in detail in Hashes and Digital Signatures.


Alternatives to Storing Session Keys

Instead of storing a random session key blob, a derived key can be used. Derived session keys are created with a password by using the CryptDeriveKey function. In this way, instead of storing a particular derived key, an application can create a derived key as needed by prompting the user for the password.

Stored key blobs are dependent on the stability of the public/private key pairs stored within the CSP. If these key pairs are somehow lost, (for example, through a hardware or software incident), you will be unable to decrypt your key blobs. This means that any data that has been encrypted by using these keys will also be lost. For this reason, it is recommended that you use a backup authority when storing long-term archival data.

A backup authority is a trusted application running on a secure computer that provides storage for the session keys of its clients. All session keys stored there are encrypted in the form of key blobs by using the backup authority's public key. An application using a backup authority typically follows these steps:

To use a backup authority
  1. Encrypt the file normally.
  2. Export the session key used to encrypt the file into a simple key blob, specifying that your own key exchange public key be used to encrypt the key blob. Store this key blob with the encrypted file.
  3. Export the session key again, this time specifying that the backup authority's public key be used to encrypt the key blob. Send this key blob to the backup authority, along with the key's description, serial number, and so on.

If, at a later time, you lose your key pairs, you can retrieve the session keys from the backup authority. You will first have to establish your identity to the backup authority. The procedure for doing this is determined by the policy of the particular backup authority, and does not involve the CryptoAPI.


Exchanging Public Keys

Exchanging public keys is the first step that two users contemplating encrypted communication need to take. After doing this, the users can send encrypted and signed data to each other in a straightforward manner.

There are two fundamental ways to obtain each other's public keys:

  • The users can obtain each other's public keys in the form of certificates, from a certification authority. This is the most secure way to exchange public keys that does not require user interaction.
  • The users can read their public keys to each other over the telephone, use certified mail to send them to each other, or use another method that is reasonably tamperproof. Note that your public key is not secret, so that it doesn't matter if it is overheard by a third party.

    This method can also be used to validate the public key values that have been exchanged in some other manner.


Certificates and Certification Authorities

A certificate is a packet of data that contains a user's public key, in addition to the data that serves to identify the user in the real world (for example, the user's name). Every certificate is created and signed by a trusted entity known as a certification authority.

Because certificates are signed, they can be transmitted over a nonsecure network or stored on nonsecure media. Each time you receive a certificate, you should verify the signature by using the certification authority's public key.

For more information on certificates see Authentication Using Certificates, and Managing Certificates.

Warning If you use the Microsoft Base Cryptographic Provider to create a certification authority, your license to issue certificates is limited to certificates intended for use in the context of your particular application or service.


Exchanging Public Keys Manually

If a certification authority is not available, or if one or more of the users have not registered their public keys with it, then the users need to exchange their public keys in some other manner. This can also be done if the certification authority is not considered trustworthy by one or more of the users.

When transferring keys or messages from one user to another, one of the users is designated the sending user (or sender, who uses the sending application) and the other the destination user (or receiver, who uses the receiving application).

The first step is for the sender to export his public key from the CSP into a public key blob by using the CryptExportKey function. Next, the key blob must be sent to the receiver in some secure manner (for example, the sender might hand carry it on a floppy disk to the receiver). Although secrecy is not necessary, both users must be confident that the integrity of the key blob remains untarnished during the transfer. The mechanics of how this is done are completely independent of the CryptoAPI.

Public key blobs are not encrypted. Thus, it would not be difficult for the sending application to convert the key blob to a readable format, so that the sender could read the public key to the receiver over the telephone. Furthermore, it would not be difficult for the receiving application to reconstruct the public key blob.

After the receiving application has received the key blob data from the sending application, it imports the key blob into its own CSP. This is done by using the CryptImportKey function.


Exchanging Session Keys

To send another user an encrypted message, you must send that user the session key that was used to perform the encryption. There are two ways to approach this:

  • The sending user can create a random session key, encrypt it by using the receiver's public key, and send the encrypted key (key blob) to the receiver. This approach is discussed in the following section.
  • The sending and receiving users can mutually agree on a session key by exchanging several messages back and forth. The users can then use this session key to send and receive encrypted messages. See Sample Three-Phase Exchange Protocol for a sample three-phase key exchange protocol that can be used for this purpose. Designing one of these protocols is fairly difficult and should only be attempted by an experienced cryptographer.

Note The procedure described in the following section assumes that the users (or CryptoAPI clients) already possess their own set of public/private key pairs and have also obtained each other's public keys.


Sending an Encrypted Session Key

The easiest way to send encrypted messages to another user is to send the message (encrypted with a random session key) along with the session key (encrypted with the receiver's key exchange public key). These are the steps for sending an encrypted session key:

To send and encrypted session key
  1. Create a random session key by using the CryptGenKey function.
  2. Encrypt the message by using the session key. This procedure is discussed in Encrypting and Decrypting Data.
  3. Export the session key into a key blob with the CryptExportKey function, specifying that the key be encrypted with the destination user's key exchange public key.
  4. Send both the encrypted message and the encrypted key blob to the destination user.
  5. The destination user should then import the key blob into his or her CSP by using the CryptImportKey function. This will automatically decrypt the session key, provided the destination user's key exchange public key was specified in step 3.
  6. The destination user can then decrypt the message by using the session key, following the procedure discussed in Encrypting and Decrypting Data.

Sending an Encrypted Message with a Key Blob

The following illustration shows how to use this procedure to send an encrypted message.

This approach is vulnerable to at least one common form of attack. An eavesdropper can acquire copies of one or more encrypted messages and the encrypted keys. Then, at some later time, the eavesdropper can send one of these messages to the receiver and the receiver will have no way of knowing the message did not come directly from the original sender. This risk can be reduced by timestamping all messages or by using serial numbers. Using a three-phase key exchange protocol will eliminate this problem entirely. See Sample Three-Phase Exchange Protocol.


Key Blobs Explained

Key blobs provide a way to store keys outside of the CSP. In Generating Cryptographic Keys it states that keys are always kept inside the CSP for safekeeping, and that applications are allowed access to the key only through a handle. Key blobs are the one exception to this rule.

Key blobs are created by exporting an existing key out of the provider by using the CryptExportKey function. Later, the key blob can be imported into a provider (often a different CSP on a different computer) by using the CryptImportKey function. This will create a key in the CSP that is a duplicate of the one that was exported. In this way, key blobs are used as the medium for securely transferring keys from one CSP to another.

Key blobs consist of a standard header, followed by data (a string of unintelligible bytes) that represents the key itself. If the key blob contains a session key, then this data is always kept encrypted. Applications do not access the internals of key blobs. It was this characteristic of being an inaccessible, unintelligible string of bytes that led to the name "key blob."

Key blobs are personalized in that they are encrypted with the key exchange public key of the intended recipient. This makes them fairly secure. To make them tamperproof, keys are sometimes signed with the key exchange private key of the originating user.

For details on the key blobs associated with particular providers, see the key blob sections of Microsoft Cryptographic Service Providers.

There are currently three types of key blobs defined:

  • Simple key blobs
  • Public key blobs
  • Private key blobs


Simple Key Blobs

A simple key blob (SIMPLEBLOB) is a session key encrypted with the key exchange public key of the destination user. This key blob type is used when storing a session key or transmitting a session key to another user.

The Microsoft Base Cryptographic Service Provider format of simple key blobs is fully documented in The Base Provider Simple-Key Blob.


Public Key Blobs

A public key blob (PUBLICKEYBLOB) contains the public key portion of a public/private key pair. Unlike simple key blobs, these are not encrypted.

When communicating with someone who is not using the CryptoAPI, your application may need to build one of these key blobs manually so that the other user's public keys can be imported into your CSP. In addition, it is not uncommon for an application to display the value of a public key in plaintext form so the user can validate it by hand.

The Microsoft Base Cryptographic Service Provider format of public key blobs is fully documented in The Base Provider Public-Key Blob.


Private Key Blobs

A private key blob (PRIVATEKEYBLOB) contains one complete public/private key pair. These key blobs are used by administrative programs to distribute or transport public/private key pairs (for example, between a network administrator's computer and a user's computer, or between the user's desktop computer and laptop computer). These key blobs can also be used by advanced applications where the key pairs are stored within the application, rather than relying on the CSP's storage mechanism.

As the private key portion of the key pair is extremely confidential, these blobs are typically kept encrypted with a symmetric cipher.

The Microsoft Base Cryptographic Service Provider format of private key blobs is fully documented in The Base Provider Private-Key Blob.


Sample Three-Phase Exchange Protocol

To generate an authenticated and encrypted connection between two users on a nonsecure network, the users can exchange a set of messages to negotiate a pair of encryption keys. One key is used by the sender to encrypt messages and the other is used by the receiver. This protocol ensures that both users are currently active and are sending messages directly to each other. In other words, this protocol prevents replay and man-in-the-middle attacks.

Note This section assumes that both users involved already possess their own set of public/private key pairs and that they have also obtained each other's public keys.

It is further assumed that the users have already exchanged human-readable user names. This is generally done at the same time the public keys are exchanged, because the user name is included as part of each certificate. When necessary, the public key data can be used as the user name, although this is not recommended. All that really matters, though, is that each user's user name be tightly bound to his or her public key and that both users agree on what their respective user names are.


Overview of the Sample Protocol

This protocol provides a standard way for two users to create an authenticated, real-time connection. The end result of this protocol is a session key that is shared by both of the users involved. This protocol is known as a three-phase protocol because it requires that the two users exchange three packets of data in the process of creating the shared session keys. This is shown in the following illustration.

A variety of key exchange protocols can be implemented by using the CryptoAPI. The protocol discussed here is just one of many possibilities. However, using this particular protocol will tend to increase your application's potential interoperability.

Following is a description of this protocol. One of the users is arbitrarily designated the sending user (or sender) and the other the destination user (or receiver).


Phase 1

In Phase 1, the sender creates a random session key, to be known as "session key A," by using the CryptGenKey function. The sender then uses CryptExportKey to export this key into a simple key blob, specifying that the receiver's key exchange public key be used to encrypt the key blob. This key blob is then sent to the receiver.

The receiver accepts the key blob from the sender and imports it into its CSP by using the CryptImportKey function. This function returns a handle to session key A to the receiver.


Phase 2

In Phase 2, the receiver creates a random session key, to be known as "session key B." The receiver exports this key into a key blob, specifying that the sender's key exchange public key be used to encrypt the key blob, and transmits it to the sender.

The receiver then builds up a hash value containing session key A, the receiver's name, session key B, the sender's name, and the text "phase 2." This hash value is then sent to the sending user. The details of this process are discussed in Receiver Code Example.

The data must be hashed in the standard sequence so that the sender will be able to properly validate it. The data formats used by the sender and receiver must also match, although a standard format is not specified here.

The sending user accepts the session key B key blob from the receiver, and imports it into a CSP. The hash value is also received.

The sending user then validates the receiver's hash value by creating a hash of its own containing the same data, and comparing the two hash values. If the hash values do not match, then either the destination user has not been forthright, or someone else is tampering with the data between the two users. In either case, the protocol should be terminated and the communication link severed.

If the two hash values do match, this tells the sender that the receiver is presently online and in real-time communication. This is primarily because the hash value contains session key A, which was sent out encrypted with the receiver's public key. Only the real receiver could have decrypted the session key and built the hash value. Including the human-readable user names in the hash makes it possible to involve the users in the process as an additional check.


Phase 3

In Phase 3, the sender builds up a hash value containing session key B, the sender's name, the receiver's name, and the text "phase 3." This hash value is then sent to the destination user. The details of this process are discussed in Sender Code Example.

The destination user accepts the hash value from the sender and validates it by creating a hash of its own and comparing the two hash values. If the hash values do not match, then the protocol should be terminated and the communication link severed.

If the two hash values do match, this tells the receiver that the sender is presently online and in real-time communication. This is primarily because the hash value contains session key B, which was sent out encrypted with the sender's public key. Only the real sender could have decrypted the session key and built the hash value.


Protocol Conclusion

After the two users have exchanged session keys and hash values and the hash values have been properly validated, the protocol is complete. The sender and the receiver can now use session key A and session key B respectively to send encrypted messages to each other.


Sender Code Example

This section shows the code needed on the sender's side to implement the three-phase key exchange protocol. The details of the communication between the sender and the receiver are not shown, because these will be different for each implementation.

For purposes of readability, this example and the following one, diverge from good programming practice in two major ways.

  • No error checking is shown. A working program should always check the returned error codes and perform some appropriate action when an error is encountered.
  • Fixed-length buffers are used to store key blobs and hash values. In practice, these buffers should be allocated dynamically, because this data will vary in size, depending on the CSP used.
#include <wincrypt.h>

HCRYPTPROV hProv = 0;

#define NAME_SIZE 256
BYTE pbDestName[NAME_SIZE];
DWORD dwDestNameLen;
BYTE pbSendName[NAME_SIZE];
DWORD dwSendNameLen;

HCRYPTKEY hDestPubKey = 0;
HCRYPTKEY hKeyA = 0;
HCRYPTKEY hKeyB = 0;

#define BLOB_SIZE 256
BYTE pbKeyBlob[BLOB_SIZE];
DWORD dwBlobLen;

#define HASH_SIZE 256
BYTE pbHash[HASH_SIZE];
DWORD dwHashLen;
BYTE pbDestHash[HASH_SIZE];
DWORD dwDestHashLen;
HCRYPTHASH hHash = 0;

// Get a handle to the default provider.
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);

// Obtain the receiver's exchange public key. Import it into
// the CSP and place a handle to it in 'hDestPubKey'.
...
// Obtain the receiver's name. This is usually done at the
// same time as the public key was obtained. Place this in
// 'pbDestName' and set 'dwDestNameLen' to the number of bytes in
// the name.
...

// Place the sender's name in 'pbSendName' and set
// 'dwSendNameLen' to the number of bytes in it.
...

// Create a random session key (session key A). Because this key will
// be used solely for key exchange and not encryption, it
// does not matter which algorithm you specify here.
CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyA);

// Export session key A into a simple key blob.
dwBlobLen = BLOB_SIZE;
CryptExportKey(hKeyA, hDestPubKey, SIMPLEBLOB, 0, pbKeyBlob,
                 &dwBlobLen);

// Send the key blob containing session key A to the receiver.
...

// Wait for the receiver to respond.
...

// Receive a key blob containing session key B from the
// receiver and place it in 'pbKeyBlob'. Set 'dwBlobLen' to
// the number of bytes in the key blob.
...

// Receive a hash value from the receiver and place it in
// 'pbHashValue'. Set 'dwHashLen' to the number of bytes in the hash
// value.
...

// Import the key blob into the CSP.
CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyB);

//
// Verify the hash value received from the receiver.
//

// Create a hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key A to the hash.
CryptHashSessionKey(hHash, hKeyA, 0);

// Add the receiver's  name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);

// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add "phase 2" text to the hash.
CryptHashData(hHash, "phase 2", 7, 0);

// Complete the hash computation, and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash);

//
// Compare the hash value received from the receiver with
// the hash value that we just computed. If they do not match, then
// terminate the protocol.
//

if(dwHashLen!=dwDestHashLen || memcmp(pbHash, pbDestHash, dwHashLen)) {
    printf("Key exchange protocol failed in phase 2!\n");
    printf("Aborting protocol!\n");
    return;
}

//
// Compute the hash to be sent to the receiver.
//

// Create the hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);

// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add the receiver's name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add "phase 3" text to the hash.
CryptHashData(hHash, "phase 3", 7, 0);

// Complete the hash computation and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash);

// Send the hash value to the receiver.
...

//
// Use session key A to encrypt messages sent to the receiver.
// Use session key B to decrypt messages received from the receiver.
//
...

// Destroy the session keys.
CryptDestroyKey(hKeyA);
CryptDestroyKey(hKeyB);

// Release provider handle.
CryptReleaseContext(hProv, 0);


Receiver Code Example

This section illustrates the code needed on the receiver side to implement the three-phase key exchange protocol. The details of the communication between the sender and the receiver are not shown, because these will be different for each implementation.

#include <wincrypt.h>

HCRYPTPROV hProv = 0;

#define NAME_SIZE 256
BYTE pbDestName[NAME_SIZE];
DWORD dwDestNameLen;
BYTE pbSendName[NAME_SIZE];
DWORD dwSendNameLen;

HCRYPTKEY hSendPubKey = 0;
HCRYPTKEY hKeyA = 0;
HCRYPTKEY hKeyB = 0;

#define BLOB_SIZE 256
BYTE pbKeyBlob[BLOB_SIZE];
DWORD dwBlobLen;

#define HASH_SIZE 256
BYTE pbHash[HASH_SIZE];
DWORD dwHashLen;
BYTE pbSendHash[HASH_SIZE];
DWORD dwSendHashLen;
HCRYPTHASH hHash = 0;

// Get a handle to the default provider.
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);

// Obtain the sender's exchange public key. Import it into the
// CSP and place a handle to it in 'hSendPubKey'.
...
// Obtain the sender's name. This is usually done at the
// same time the public key was obtained. Place this in
// 'pbSendName' and set 'dwSendNameLen' to the number of bytes in
// the name.
...

// Place the receiver's name in 'pbDestName' and set
// 'dwDestNameLen' to the number of bytes in the name.
...

// Receive a key blob containing session key A from the sender
// and place it in 'pbKeyBlob'. Set 'dwBlobLen' to the number of
// bytes in the key blob.
...

// Import the key blob into the CSP.
CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKeyA);

// Create a random session key (session key B). Because this key is
// going to be used solely for key exchange and not encryption, it
// does not matter which algorithm you specify here.
CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKeyB);

// Export session key B into a simple key blob.
dwBlobLen = BLOB_SIZE;
CryptExportKey(hKeyB, hSendPubKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen);

// Transmit the key blob containing session key B to the sender.
...

//
// Compute the hash value and transmit it to the sender.
//

// Create the hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key A to the hash.
CryptHashSessionKey(hHash, hKeyA, 0);

// Add the receiver's name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);

// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add "phase 2" text to the hash.
CryptHashData(hHash, "phase 2", 7, 0);

// Complete the hash computation and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash);

// Transmit the hash value to the sender.
...

// Wait for the sender to respond.
...

// Receive a hash value from the sender and place it in
// 'pbSendHashValue'. Set 'dwSendHashLen' to the number of bytes in
// the hash value.
...

//
// Verify the hash value received from the sender.
//

// Create the hash object.
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);

// Add session key B to the hash.
CryptHashSessionKey(hHash, hKeyB, 0);
// Add the sender's name to the hash.
CryptHashData(hHash, pbSendName, dwSendNameLen, 0);

// Add the receiver's name to the hash.
CryptHashData(hHash, pbDestName, dwDestNameLen, 0);

// Add "phase 3" text to the hash.
CryptHashData(hHash, "phase 3", 7, 0);

// Complete the hash computation and retrieve the hash value.
dwHashLen = HASH_SIZE;
CryptGetHashParam(hHash, HP_HASHVALUE, pbHash, &dwHashLen, 0);

// Destroy the hash object.
CryptDestroyHash(hHash));

//
// Compare the hash value received from the sender with the
// hash value that we just computed. If they do not match, then
// terminate the protocol.
//

if(dwHashLen!=dwSendHashLen || memcmp(pbHash, pbSendHash, dwHashLen)) {
    printf("Key exchange protocol failed in phase 3!\n");
    printf("Aborting protocol!\n");
    return;
}

//
// Use session key B to encrypt messages sent to the sender.
// Use session key A to decrypt messages received from the sender.
//
...

// Destroy the session keys.
CryptDestroyKey(hKeyA);
CryptDestroyKey(hKeyB);

// Destroy the handle to sender's public key.
CryptDestroyKey(hSharedKey);

// Release the provider handle.
CryptReleaseContext(hProv, 0);


Key Exchange Functions Summary

The functions described in this section are used by applications to create, configure, and destroy cryptographic keys, and to exchange them with other users. The following table briefly describes each function.

Function | Description
CryptDestroyKey | Destroy a key.
CryptExportKey | Transfer a key from the CSP into a key blob in the application's memory space.
CryptGenRandom | Generate random data.
CryptGetKeyParam | Retrieve a key's parameters.
CryptGetUserKey | Get a handle to the key exchange or signature key.
CryptImportKey | Transfer a key from a key blob to a CSP.
CryptSetKeyParam | Specify a key's parameters.


Encrypting and Decrypting Data

Encryption is the process in which data (plaintext) is translated into something that appears to be random and meaningless (ciphertext). Decryption is the process in which the ciphertext is converted back to plaintext.

A symmetric encryption key (also known here as a session key) is used during both the encryption and decryption processes. In order to decrypt a particular piece of ciphertext, you must possess the key that was used to encrypt the data. Essentially, a session key consists of a random number, of approximately 40 to 2,000 bits in length. The longer the key that is used, the more difficult it is to decrypt a piece of ciphertext without possessing the key.

The goal of every encryption algorithm is to make it as difficult as possible to decrypt the generated ciphertext without using the key. If a really good encryption algorithm is used, then there is no technique significantly better than methodically trying every possible key. Even for a key size of just 40 bits, this works out to 240 (just over 1 trillion) possible keys.

It is difficult to determine just how good an encryption algorithm is. Algorithms that look promising sometimes turn out to be very easy to break, given the proper attack. When selecting an encryption algorithm, it is probably a good idea to choose one that has been around for awhile, and has successfully resisted all attacks.


Introduction to Encryption Techniques

The Microsoft® CryptoAPI can be used by applications to easily encrypt and decrypt messages and files. This section discusses the various options available for encrypting data. For a hands-on description of how to encrypt data by using the CryptoAPI, see Encrypting Files and Messages.

The encryption algorithms available to an application depend on the cryptographic service provider (CSP) being used. However, most CSPs share most of the attributes discussed here. A symmetric algorithm is used for all data encryption performed by using the CryptoAPI, regardless of which CSP is installed.


Stream Ciphers

Stream cipher algorithms encrypt data one bit at a time. A stream of plaintext bits flows in one side, and a stream of encrypted ciphertext flows out the other. At least, this is the way it works mathematically; in practice, data is always encrypted in byte units.

Stream ciphers are not generally considered as secure as block ciphers, although this will vary depending on the particular algorithm. On the other hand, they do tend to execute faster in software. Ciphertext encrypted with stream ciphers is always the same size as the original plaintext.

Error propagation is usually less when stream ciphers are used. If a bit of ciphertext gets garbled, many stream cipher algorithms will produce only a single bit of garbled plaintext. When a block cipher is used and a ciphertext bit is garbled, at minimum an entire block's worth of plaintext will be garbled.

The only stream cipher provided with the Microsoft Base Cryptographic Provider is the RC4 stream cipher.


Block Ciphers

Block cipher algorithms encrypt data in block units, rather than a single bit at a time. The most common block size is 64 bits.

Because each block is heavily processed, block ciphers are considered more secure than stream ciphers. However, block cipher algorithms tend to execute quite a bit slower than stream ciphers.

All that the basic block encryption algorithm specifies is how to get a block of ciphertext from a block of plaintext and vice versa. All the other implementation details (for example, padding, initialization vectors, and cipher modes) are specified independently of the algorithm. These options are discussed in the next few sections.

The only block cipher provided with the Microsoft Base Cryptographic Provider is the RC2 block cipher. This algorithm has a block size of 64 bits.


Padding

Most plaintext messages will not consist of an even number of blocks. Often, the last block is short, making it necessary to add a padding string. For example, if the block length is 64 bits and the last block contains only 40 bits, then 24 bits of padding must be added.

This padding string can consist of all zeros, alternating zeros and ones, or some other pattern. Some encryption standards specify a particular padding scheme, such as the one described in the next section.

Applications using the CryptoAPI need not add padding to their plaintext before it is encrypted, nor do they have to remove it after decrypting. This is all handled automatically by the CryptoAPI.

PKCS Padding

This padding scheme is defined by RSA Data Security, Inc. and is documented in Public-Key Cryptography Standards (PKCS), PKCS #5, section 6.2.

When this method is used, a padding string is always added, even if the plaintext message divides evenly into blocks. The padding string consists of a sequence of bytes, each of which is equal to the total number of bytes in the padding string. If 24 bits of padding need to be added, then the padding string is "03 03 03" (3 bytes times 8 bits equals 24 bits). Therefore, if 64 bits of padding needs to be added, then the string is "08 08 08 08 08 08 08 08."


Cipher Modes

When a block cipher is used, any one of the following cipher modes can be specified via the CryptSetKeyParam function. If the application does not explicitly specify one of these modes, then the cipher block chaining (CBC) cipher mode is used.

Electronic Codebook (ECB) Mode

When this cipher mode is used, each block is encrypted individually. No feedback is used. This means any blocks of plaintext that are identical and are either in the same message, or in a different message that is encrypted with the same key, will be transformed into identical ciphertext blocks.

If the plaintext to be encrypted contains substantial repetition, then it is feasible for the ciphertext to be broken one block at a time. Furthermore, it is possible for an unscrupulous person to substitute and exchange individual blocks without detection.

Initialization vectors cannot be used with this cipher mode.

If a single bit of the ciphertext block is garbled, then the entire corresponding plaintext block will also be garbled.

Cipher Block Chaining (CBC) Mode

This cipher mode introduces feedback. Before each plaintext block is encrypted, it is combined with the ciphertext of the previous block by a bitwise XOR. This ensures that even if the plaintext contains many identical blocks, they will each encrypt to a different ciphertext block.

The initialization vector is combined with the first plaintext block by a bitwise XOR before the block is encrypted.

As with the electronic codebook cipher mode, if a single bit of the ciphertext block is garbled, then the corresponding plaintext block will also be garbled. In addition, a bit in the subsequent plaintext block (in the same position as the original garbled bit) will be garbled. Synchronization errors are fatal. If there are extra or missing bytes in the ciphertext, the plaintext will be garbled from that point on.

When the Microsoft Base Cryptographic Provider is used, this is the default cipher mode.

Cipher Feedback (CFB) Mode

The cipher feedback mode lets you process small increments of plaintext into ciphertext, instead of processing an entire block at a time. This is useful, for example, when encrypting a stream of data that originates at a keyboard. Each keystroke can be encrypted and transmitted without the need to wait for an entire block to be typed.

This mode uses a shift register that is one block size in length and divided up into sections. For example, if the block size is 64 bits with eight bits processed at a time, then the shift register would be divided up into eight sections.

To use the cipher feedback mode
  1. Encrypt the block in the shift register by using typical procedures.
  2. Use a bitwise XOR operator to combine the left-most 8 bits in the encrypted shift register with the next eight bits of plaintext and send them as eight bits of ciphertext.
  3. Shift the shift register 8 bits to the left.
  4. Place the 8 bits of ciphertext generated in step 2 in the right-most 8 bits of the shift register.

In the CryptoAPI, the number of bits processed at one time is specified by using the CryptSetKeyParam function to set the encryption key's KP_MODE_BITS parameter. This parameter typically defaults to eight bits.

Depending on the value of the KP_MODE_BITS parameter, this cipher mode is substantially slower than the cipher block chaining mode. For example, if the block size is 64 bits and 8 bits are processed at a time, this cipher mode is 64/8 or eight times slower.

Before the encryption process begins, the shift register is filled with the initialization vector.

If a bit in the cipher text is garbled, one plaintext bit is garbled and the shift register is corrupted. This results in the next several plaintext increments being garbled until the bad bit is shifted out of the shift register. In the preceding example, nine bytes of plaintext would be garbled. This is the same amount of error propagation as with the cipher block chaining mode. Synchronization errors are not fatal, provided that the slip is a multiple of KP_MODE_BITS. Thus, if KP_MODE_BITS is eight and there are extra or missing bytes from the ciphertext, then 9 bytes of plaintext are garbled and the plaintext will have the same number of extra or missing bytes.

Output Feedback (OFB) Mode

This mode is similar to the cipher feedback mode. The only difference between the two modes is how the shift register is filled.

The output feedback (OFB) cipher mode uses the following procedure for each encryption cycle.

To use the Output Feedback Mode
  1. Encrypt the block in the shift register by using typical procedures.
  2. Use a bitwise XOR operator to combine the leftmost 8 bits in the encrypted shift register with the next 8 bits of plaintext and send them as 8 bits of ciphertext.
  3. Shift the shift register 8 bits to the left.
  4. Place the 8 bits of ciphertext generated in step 2 in the rightmost 8 bits of the shift register.

As with the cipher feedback mode, the shift register is filled with the initialization vector before the encryption process starts.

If a bit in the cipher text is garbled, the corresponding bit of plaintext will also be garbled. This is much better than the cipher feedback mode. However, synchronization errors are fatal. If there are extra or missing bits from the ciphertext, then the plaintext will be garbled from that point on.

Note According to Gait (see reference below), the OFB block cipher mode has a weakness when the number of bits fed back is different than the block size. It is thus recommended that the KP_MODE_BITS parameter be set to the block size when this cipher mode is used.

*Gait, J. "A New Nonlinear Pseudorandom Number Generator." IEEE Transactions on Software Engineering. v. SE-3, n. 5, September 1977, 359-363.


Initialization Vectors

An initialization vector is a random number, usually the same number of bits as the block size, that is used as a starting point when encrypting a set of data. Initialization vectors are used only with those cipher modes that make use of feedback. This ensures that the effect of the initialization vector is propagated throughout the entire plaintext message being encrypted.

If initialization vectors are not used, then when two identical plaintext messages are encrypted with the same key, two identical ciphertext messages are generated. However, if each plaintext message is encrypted with a different initialization vector, the ciphertext messages generated are completely different.

You should always encrypt each message with a different initialization vector, particularly when the messages contain a large amount of duplication.

Applications using the CryptoAPI are responsible for transmitting the initialization vector along with the encrypted message. There is no need to encrypt this vector.


Salt Values

Salt values make up a portion of many session keys, as shown in the following illustration, which depicts the structure of a session key.

As with the key bits, the salt bits also consist of random data. The difference is that the key bits must be kept secret at all costs, while the salt values are made public. When exchanging keys by using the CryptoAPI, the key bits are transmitted inside of encrypted key blobs. The salt bits, on the other hand, are transmitted in plaintext form.

The size of the salt values will vary, depending on the CSP used. For example, the Microsoft Base Cryptographic Provider uses salt values of 88 bits and key values of 40 bits, for a total key size of 128 bits. Even though the salt bits make up part of each encryption key, they are usually ignored when discussing keys and key sizes. That is, when talking about Microsoft Base Cryptographic Provider encryption keys, we refer to them as 40-bit keys.

Salt values are most useful when transmitting or storing large numbers of nearly identical packets by using the same encryption key. Normally, two identical packets would encrypt into two identical ciphertext packets. However, this would indicate to an eavesdropper that the packets are identical and, thus, the packets could be attacked simultaneously. But, if the salt value is changed with every packet sent, then a completely different ciphertext packet will always be generated, even if the plaintext packets are the same.

Because salt values need not be kept secret and can be transmitted in plaintext form bundled with each ciphertext packet, it is much easier to change salt values once per packet than it would be to change the key value itself.

Applications should generate salt values with the CryptGenRandom function. It is important that each salt value be completely different than the other ones, particularly when using stream ciphers.


Common Encryption Algorithms

This section briefly describes each of the encryption algorithms supplied with the Microsoft Base Cryptographic Provider. The internal details of these algorithms are well beyond the scope of this document. For a list of additional reading material, refer to Related Documentation.

The following table lists several encryption algorithms, along with some performance benchmarks. This table was generated by an application using the CryptoAPI on a 120-MHz, Pentium-based computer. These figures are for comparison purposes only.

Cipher | Cipher Type | Key Setup Time (microseconds) | Encryption Speed (bytes/second)
DES | 64-bit block | 460 | 1,138,519
RC2 | 64-bit block | 40 | 286,888
RC4 | stream | 151 | 2,377,723


RC2 Block Cipher

The RC2 block cipher algorithm was developed by RSA Data Security, Inc. The details of this algorithm have not been published.

RC2 is a variable-key-length cipher. However, when using the CryptoAPI with the Microsoft Base Cryptographic Provider, the key length is hard-coded to 40 bits. The block size is fixed at 64 bits.


RC4 Stream Cipher

The RC4 stream cipher was developed by RSA Data Security, Inc. The details of this algorithm have not been published.

RC4 is a variable-key-length cipher. However, when using the CryptoAPI with the Microsoft Base Cryptographic Provider, the key length is hard-coded to 40 bits.


RSA Public-Key Cipher

The RSA public-key cipher was developed by (and named after) Ron Rivest, Adi Shamir, and Leonard Adleman, in the late 1970s. This algorithm is very well known—you can read about its internal details in any book on cryptography.

RSA is used by many CSPs to encrypt and decrypt keys and to generate and verify digital signatures. This algorithm is used when operations are performed by using either the key exchange or digital signature key pair. When using the CryptoAPI, this algorithm cannot be used to encrypt bulk data.

RSA is a variable-key-length cipher. However, when using the CryptoAPI with the Microsoft Base Cryptographic Provider, the key length is hard-coded to 512 bits.


Encrypting Files and Messages

To encrypt a file so that only the current user can access its data, the file is bulk encrypted with a symmetric cipher. The key to this cipher is then kept in an access block (key blob) that can be opened only with the user's private key. Note that this technique also works for encrypting messages for specific recipients.


Encrypting Messages Using CryptoAPI

Encrypting Messages Using the CryptoAPI

The following procedure describes how to encrypt a message by using the base cryptographic functions. If you want to encrypt messages by using the PKCS#7 standards, see Using Low-Level Message Functions and Using Simplified Message Functions.

To encrypt a message
  1. Generate a session key by using the CryptGenKey function.

    Making this call generates a random key and returns a handle so the key can be used to encrypt and decrypt data. The encryption algorithm to use is also specified at this point. Because the CryptoAPI does not permit applications to use public-key algorithms to encrypt bulk data, you should specify a symmetric algorithm such as RC2 or RC4, with the CryptGenKey call.

  2. Alternatively, use the CryptDeriveKey function to transform a password into a key suitable for encryption.

    If an application needs to encrypt the message in such a way that anyone with a given password can decrypt the data, the CryptDeriveKey function should be used to transform the password into a key suitable for encryption. Note that, in this case, this function is called instead of the CryptGenKey function and the subsequent CryptExportKey calls are not needed.

  3. If necessary, set extra cryptographic properties of the key by using the CryptSetKeyParam function

    After the key has been generated, extra cryptographic properties of the key can be set with the CryptSetKeyParam function. For example, this function allows different sections of the file to be encrypted with different key salts and provides a way to change the cipher mode or initialization vector of the key. These parameters can be used to make the encryption conform with a particular data encryption standard.

  4. Encrypt the data in the file with the CryptEncrypt function.

    The CryptEncrypt function takes a session key, which was generated in the previous step, and encrypts a buffer of data. Note that as the data is encrypted, the data may be slightly expanded by the encryption algorithm. The application is responsible for remembering the length of the encrypted data so the proper length can later be given to the CryptDecrypt function.

  5. Optionally, use the CryptExportKey function to allow the current user to decrypt the data in the future.

    To allow the current user to decrypt the data in the future, the CryptExportKey function is used to save the decryption key in an encrypted form (a key blob) that can only be decrypted with the user's private key. This function requires the user's key exchange public key for this purpose, which can be obtained by using the CryptGetUserKey function. The CryptExportKey function will return a key blob that must be stored by the application for use in decrypting the file.

Note If the application has certificates (or public keys) for other users, it can permit other users to decrypt the file by performing CryptExportKey calls for each user it wants to give access. The returned key blobs must be stored by the application, as in step 5.


Structure of an Encrypted File

There are a number of standard formats for encrypted files and messages. These are designed to make it easier for different applications to communicate. An explanation of these formats falls outside the scope of this document. For a list of additional reading material, refer to Related Documentation.

After a file or message has been encrypted, the following data must be stored by the application and is usually kept bundled together:

  • The encrypted data. When a block cipher is used, the data is padded out to a multiple of the cipher's block size. Padding is often added even when the original message is already an even multiple. When a stream cipher is used, the encrypted data is generally the same size as the original plaintext.
  • One or more key blobs, each containing the session key used to encrypt the message. Each of these key blobs is encrypted with the key exchange public key of a user who will later decrypt the data. Note that these are not stored if the key was derived from a password. Instead, when it is time to decrypt the message, the session key is recreated from the password. The password itself must be remembered by the user.
  • Any salt values that were specified as the data was being encrypted. When the data is decrypted, these values will have to be specified (by using the CryptSetKeyParam function) in the same manner as the data encryption process.
  • Any initialization vectors that were specified as the data was being encrypted. These values are handled in much the same way as the salts.

All parameters that were specified with the CryptSetKeyParam function as the message was being encrypted must also be specified as the message is decrypted. It may be appropriate to store some of these parameters with the encrypted message as well.


Encryption Example

This example reads data from a text file (test1.txt), encrypts it by using the RC2 block cipher, and writes out the encrypted data to another file (test1.xxx). A random session key is generated to perform the encryption and is stored to the output file, along with the encrypted data. Note that this session key is encrypted with the current user's key exchange public key by the CryptExportKey function.

#include <wincrypt.h>

FILE *hSource = NULL;
FILE *hDest = NULL;
int eof = 0;

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTKEY hXchgKey = 0;

#define BLOCK_SIZE 160
#define BUFFER_SIZE (BLOCK_SIZE+16) // Give buffer 16 bytes of extra
                                    // room for padding, and so forth.
BYTE pbBuffer[BUFFER_SIZE];
DWORD dwCount;

BYTE *pbKeyBlob = NULL;
DWORD dwBlobLen;

// Open the source file that contains the data to be encrypted.
if((hSource=fopen("test1.txt","rb"))==NULL) {
    printf("Error opening source file!\n");
    goto done;
}

// Open the destination file.
if((hDest=fopen("test1.xxx","wb"))==NULL) {
    printf("Error opening destination file!\n");
    goto done;
}

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Get a handle to key exchange key.
if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) {
    printf("Error %x during CryptGetUserKey!\n", GetLastError());
    goto done;
}

// Create a random block cipher session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptGenKey!\n", GetLastError());
    goto done;
}

// Determine the size of the key blob and allocate memory.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen)) {
    printf("Error %x computing blob length!\n", GetLastError());
    goto done;
}
if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
    printf("Out of memory!\n");
    goto done;
}

// Export the key into a simple key blob.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob,
        &dwBlobLen)) {
    printf("Error %x during CryptExportKey!\n", GetLastError());
    free(pbKeyBlob);
    goto done;
}

// Write the size of the key blob to the destination file.
fwrite(&dwBlobLen, sizeof(DWORD), 1, hDest);
if(ferror(hDest)) {
    printf("Error writing header!\n");
    free(pbKeyBlob);
    goto done;
}

// Write the key blob to the destination file.
fwrite(pbKeyBlob, 1, dwBlobLen, hDest);
if(ferror(hDest)) {
    printf("Error writing header!\n");
    free(pbKeyBlob);
    goto done;
}

// Free memory.
free(pbKeyBlob);

// Encrypt the source file and write it to the destination file.
do {
    // Read up to BLOCK_SIZE bytes from source file.
    dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource);
    if(ferror(hSource)) {
        printf("Error reading data!\n");
        goto done;
    }
    eof=feof(hSource);

    // Encrypt the data.
    if(!CryptEncrypt(hKey, 0, eof, 0, pbBuffer, &dwCount,
                                                  BUFFER_SIZE))
    {
        printf("Error %x during CryptEncrypt!\n", GetLastError());
        goto done;
    }

    // Write the data to the destination file.
    fwrite(pbBuffer, 1, dwCount, hDest);
    if(ferror(hDest)) {
        printf("Error writing data!\n");
        goto done;
    }
} while(!feof(hSource));

done:

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);

// Destroy the key exchange key.
if(hXchgKey != 0) CryptDestroyKey(hXchgKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

// Close the source file.
if(hSource != NULL) fclose(hSource);

// Close destination file.
if(hDest != NULL) fclose(hDest);


Decrypting Messages Using CryptoAPI

Decrypting Messages by Using the CryptoAPI

If a message was encrypted for a particular user, then the CryptGenKey function was used to create a random session key before the encryption was performed. This means that before the message can be decrypted, the key blob containing the session key needs to be imported into the CSP with the CryptImportKey function. This function will use your key exchange private key to decrypt the key blob. This means that the key blob must have been originally created by using the matching key exchange public key.

If the message was encrypted so that any password holder can access the data, the CryptImportKey function is not used. Instead, you create the decryption session key with the CryptDeriveKey function. You will also need to supply the function with the password (or other access token).

The session key's parameters need to be configured in the same way they were during encryption. These parameters can be specified by using the CryptSetKeyParam function. For example, if the salt value was changed one or more times during the encryption process, then it must also be changed during the decryption process in exactly the same manner.

The message is decrypted by using the CryptDecrypt function. If the message is too large to fit comfortably in memory, it can be decrypted in sections, through multiple calls to CryptDecrypt.

When the decryption is complete, be sure to destroy the session key by using the CryptDestroyKey function. In addition to destroying the key, this will free up CSP resources.


Decryption Example

This example reads the encrypted data from the file created by the Encryption Example (test1.xxx), decrypts it by using the RC2 block cipher, and writes out the plaintext data to another file (test1.txt). The session key used to perform the decryption is read from the ciphertext file.

#include <wincrypt.h>

FILE *hSource = NULL;
FILE *hDest = NULL;
int eof = 0;

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;

#define BLOCK_SIZE 160
BYTE pbBuffer[BLOCK_SIZE];
DWORD dwCount;

BYTE *pbKeyBlob = NULL;
DWORD dwBlobLen;

// Open the source file.
if((hSource=fopen("test1.xxx","rb"))==NULL) {
    printf("Error opening source file!\n");
    goto done;
}

// Open the destination file.
if((hDest=fopen("test2.txt","wb"))==NULL) {
    printf("Error opening destination file!\n");
    goto done;
}

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Read the key blob length from the source file and allocate it to memory.
fread(&dwBlobLen, sizeof(DWORD), 1, hSource);
if(ferror(hSource) || feof(hSource)) {
    printf("Error reading file header!\n");
    goto done;
}

if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
    printf("Out of memory!\n");
    goto done;
}

// Read the key blob from the source file.
fread(pbKeyBlob, 1, dwBlobLen, hSource);
if(ferror(hSource) || feof(hSource)) {
    printf("Error reading file header!\n");
    goto done;
}

// Import the key blob into the CSP.
if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey)) {
    printf("Error %x during CryptImportKey!\n", GetLastError());
    goto done;
}

// Decrypt the source file and write it to the destination file.
do {
    // Read up to BLOCK_SIZE bytes from source file.
    dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource);
    if(ferror(hSource)) {
        printf("Error reading data from source file!\n");
        goto done;
    }
    eof=feof(hSource);

    // Decrypt the data.
    if(!CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount)) {
        printf("Error %x during CryptDecrypt!\n", GetLastError());
        goto done;
    }

    // Write the data to the destination file.
    fwrite(pbBuffer, 1, dwCount, hDest);
    if(ferror(hDest)) {
        printf("Error writing data to destination file!\n");
        goto done;
    }
} while(!feof(hSource));

// If the decryption was successful, The data contained in test2.txt
// should match the data contained in the original test1.txt ( which
// was used as the source for the encryption in the previous section).

done:

// Free memory.
if(pbKeyBlob) free(pbKeyBlob);

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

// Close the source file.
if(hSource != NULL) fclose(hSource);

// Close destination file.
if(hDest != NULL) fclose(hDest);


Encrypting and Decrypting Simultaneously

Care must be taken when encrypting or decrypting two streams of data simultaneously with the same cryptographic key. The same physical session key must not be used for both operations, because every session key contains internal state information and it will get mixed up if used for more than one operation at a time. A simple solution to this problem is to make a copy of the session key. In this way, the original key can be used for one operation and the copy used for the other.

Copying a session key is done by exporting the key with CryptExportKey and then by using CryptImportKey to import it back in. When the key is imported, the CSP will give the new key its own section of internal memory, as if it were not related at all to the original key.

The following code fragment shows how a copy of a session key can be obtained.

HCRYPTPROV hProv;    // Handle to a CSP.
HCRYPTKEY hKey;      // Handle to a session key.

HCRYPTKEY hCopyKey = 0;
HCRYPTKEY hPubKey = 0;
BYTE pbBlob[256];
DWORD dwBlobLen;

// Get a handle to the current user's key exchange public key.
CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hPubKey);

// Export the session key into a key blob.
dwBlobLen = 256;
CryptExportKey(hKey, hPubKey, SIMPLEBLOB, 0, pbBlob, &dwBlobLen);

// Import the session key back into the CSP. This is stored separately
// from the original session key.
CryptImportKey(hProv, pbBlob, dwBlobLen, 0, 0, &hCopyKey);

// Use 'hKey' for one set of operations and 'hCopyKey' for the other.
...

Note that this technique should not be used with stream ciphers, as stream cipher keys should never be used more than once. Instead, separate transmit and receive keys should be used.


Data Encryption Functions Summary

The functions in this section support encryption and decryption operations. Before invoking these functions, you must first acquire an encryption key. This is done by using the functions CryptGenKey, CryptDeriveKey, or CryptImportKey. The encryption algorithm is specified when the key is created. You can also specify additional encryption parameters by using the CryptSetKeyParam function.

Function | Description
CryptEncrypt | Encrypt a section of plaintext by using the specified encryption key.
CryptDecrypt | Decrypt a section of ciphertext by using the specified encryption key.


Hashes and Digital Signatures

Using the functions described in this chapter, a user can digitally sign data so that any other user can easily verify that the data has not been changed since it was signed. The identity of the user who signed the data can also be easily verified.

A digital signature consists of a small amount of binary data, typically less than 256 bytes. This signature can be bundled with the signed message or stored separately; depending on how a particular application has been implemented.

The Microsoft® Base Cryptographic Provider creates digital signatures that conform to the RSA Public-Key Cryptography Standard (PKCS) #6.


How Digital Signatures Work

There are two steps involved in creating a digital signature from a message. The first step involves creating a hash value (also known as a message digest) from the message. This hash value is then signed, using the private key of the signer. Following is an illustration of the steps involved in creating a digital signature.

To verify a signature, both the message and the signature are required. First, a hash value must be created from the message in the same way the signature was created. This hash value is then verified against the signature, by using the public key of the signer. If the hash value and the signature match, you can be confident that the message is indeed the one the signer originally signed and that it has not been tampered with. The following diagram illustrates the process involved in verifying a digital signature.

A hash value consists of a small amount of binary data, typically around 160 bits. This is produced by using a hashing algorithm. A number of these algorithms are listed later in this section.

All hash values share the following properties, regardless of the algorithm used:

  • The length of the hash value is determined by the type of algorithm used, and its length does not vary with the size of the message. The message can be several kilobytes or several gigabytes, it doesn't matter. The most common hash value lengths are either 128 or 160 bits.
  • Every pair of nonidentical messages will translate into a completely different hash value, even if the two messages differ only by a single bit. Using today's technology, it is not feasible to discover a pair of messages that translate to the same hash value without breaking the hashing algorithm.
  • Each time a particular message is hashed using the same algorithm, the exact same hash value will be produced.
  • All hashing algorithms are one-way. Given a hash value, it is not possible to recover the original message. In fact, none of the properties of the original message can be determined given the hash value alone.


Signing and Verifying Messages

To apply a digital signature to a piece of data, a secure hash function is used to build a digest of the data (for example, a 160-bit hash value), which is then transformed with the private key of the signer. Other users can then check the authenticity of the signature by reconstructing the hash value, and checking it against the inverse of the digital signature data. The Microsoft CryptoAPI abstracts the actual method of doing the signature, so that application developers need not be aware of the details of the signature mechanics.


Signing Data

In order to sign data, a hash object must first be created by using the CryptCreateHash function. This hash object will accumulate the data to be signed. Next, the data is added to the hash object with the CryptHashData function.

After the last block of data is added to the hash, the CryptSignHash function is used to sign the hash. A description of the data can also be added to the hash object at this point. After the digital signature data has been obtained, the hash object should be destroyed with the CryptDestroyHash function.

Hashes can be signed with either the signature private key or the key exchange private key. The signature key should be used when the user who owns the signature key is signing some of his or her data. The key exchange key should be used when signing data that does not directly belong to the user. The classic example of this is when the key exchange key is used to sign session keys during a key exchange protocol.


Verifying Signatures

To verify a signature, a hash object must first be created by using the CryptCreateHash function. This hash object will accumulate the data to be verified. The data is then added to the hash object with the CryptHashData function.

After the last block of data is added to the hash, the CryptVerifySignature function is used to verify the signature. The signature data, a handle to the hash object, and the description string must all be supplied to CryptVerifySignature. A handle to the key pair that was used to sign the data must also be specified.

After the signature has been verified (or has failed the verification) the hash object should be destroyed with the CryptDestroyHash function.


Obtaining the Hash Value

To obtain the hash value, a hash object must first be created by using the CryptCreateHash function. This object will accumulate the data to be verified. The data is then added to the hash object with the CryptHashData function.

After the last block of data is added to the hash, the CryptGetHashParam function is used to obtain the hash value.

After the hash value has been obtained, the hash object should be destroyed with the CryptDestroyHash function.


Hashing and Signature Algorithms

This section lists several algorithms used to compute hashes and digital signatures. Each of these algorithms is supported by the Microsoft Base Cryptographic Provider. However, the internal details of these algorithms are well beyond the scope of this document. For a list of additional sources refer to Related Documentation.


MD2, MD4, and MD5

The MD2, MD4, and MD5 hashing algorithms were all developed by RSA Data Security, Inc. These algorithms were developed in sequential order, with the later algorithms being better (more secure) than the earlier ones. All three generate 128-bit hash values. Of the three algorithms, MD5 is recommended.

These algorithms are well known and can be reviewed in detail in any reference on cryptography.


Secure Hash Algorithm (SHA)

The SHA hashing algorithm was developed by the National Institute of Standards and Technology (NIST) and by the National Security Agency (NSA). This algorithm was developed for use with DSA (Digital Signature Algorithm) or DSS (Digital Signature Standard).

This algorithm generates a 160-bit hash value.


SSL3 Client Authentication Algorithm

This algorithm is used for SSL3 client authentication. In the SSL3 protocol, a concatenation of an MD5 hash and an SHA hash is signed with an RSA private key. CryptoAPI and the Microsoft Base and Enhanced Cryptographic Providers support this with the hash type CALG_SSL3_SHAMD5.

To create a CALG_SSL3_SHAMD5 hash
  1. Using standard CryptoAPI methodology, create MD5 and SHA hashes of the target data.
  2. Concatenate the two hashes, with the MD5 value leftmost and the SHA value rightmost. This results in a 36 byte value (16 bytes + 20 bytes).
  3. Get a handle to a hash object by calling CryptCreateHash with CALG_SSL3_SHAMD5 passed in the Algid argument.
  4. Set the hash value with a call to CryptSetHashParam. The concatenated hash values are passed as a BYTE* in the pbData argument, and the HP_HASHVAL value must be passed in the dwParam argument. Note that CryptHashData should not be called using the handle returned by CryptCreateHash in step 3. Such a call will fail.
  5. Call CryptSignHash to generate the signature.
  6. Call CryptDestroyHash to destroy the hash object.

CSPs that are intended to be compatible with the Microsoft RSA Providers, rsabase.dll and rsaenh.dll, must implement this functionality. This ALG_ID is used by the Microsoft schannel.dll when performing client authentication with SSL3 in the Microsoft Internet Explorer.


Message Authentication Code (MAC)

Message Authentication Code (MAC) algorithms are similar to hash algorithms, but are computed by using a symmetric (session) key. Because of this difference, you must possess the session key in order to recompute the hash value to verify that the base data has not changed. These algorithms are sometimes called keyed-hash algorithms. To see which Microsoft providers support MAC, see Microsoft Cryptographic Service Providers.


Cipher Block Chaining (CBC) MAC

One of the algorithms (CALG_MAC) implemented by Microsoft providers is of the most common sort. That is, it is a block cipher MAC. This method encrypts the base data with a block cipher and then uses the last encrypted block as the hash value. The encryption algorithm used to build the MAC is the one that was specified when the session key was created. (For more information on block ciphers, see Block Ciphers.)


HMAC

Another algorithm (CALG_HMAC) implemented by Microsoft providers is known as HMAC. This algorithm also uses a secret symmetric key to create the hash, but is more complex than the simple CBC MAC algorithm. It can be used with any iterated cryptographic hash algorithm, such as MD5 or SHA-1.

The following expression is used to calculate an HMAC:

H( K XOR OuterString, H( K XOR InnerString, text ))

Where:

H
Denotes the cryptographic hash algorithm to be used. It must be of a type where data is hashed by iterating a basic compression function on blocks of data.
K
The secret (symmetric) key that is to be used.
InnerString
A fixed byte string.
OuterString
A fixed byte string.
text
The data that is to have the HMAC applied to it.
To compute an HMAC by using the CryptoAPI
  1. Get a pointer to the Microsoft Cryptographic Provider by calling CryptAcquireContext.
  2. Create a handle to an HMAC hash object by calling CryptCreateHash. CALG_HMAC should be passed in the Algid argument and the handle of a symmetric key in the hKey argument. This is the key that is used in computing the HMAC.
  3. Specify the the type of hash to be used by calling CryptSetHashParam with the dwParam argument set to the value HP_HMAC_INFO. The pbData argument must point to an initialized HMAC_INFO structure.
  4. Call CryptHashData to begin computing the HMAC of the data. The first call to CryptHashData causes the key value to be XORed with the inner string and the data. The result of the XOR is hashed and then the target data for the HMAC (pointed to by the pbData argument passed in the call to CryptHashData) is hashed. If necessary, subsequent calls to CryptHashData may then be made to finish the hashing of the target data.
  5. Call to CryptGetHashParam with the dwParam argument set to HP_HASHVAL. This call causes the inner hash to be finished and the outer string to be XORed with the key. The result of the XOR is hashed and then the result of the inner hash (completed in the previous step) is hashed. The outer hash is then finished and returned in the pbData argument and the length in the pdwDataLen argument.

Warning The same symmetric (session) key should not be used for both message encryption and MAC generation. Doing so greatly increases the risk of your messages being decoded by attackers.


Hashing and Digital Signature Functions Summary

The functions described in this section are used by application developers to compute hashes (also known as message digests), and are also used to create and verify digital signatures. The following table briefly describes each function.

Function | Description
CryptCreateHash | Create an empty hash object.
CryptDestroyHash | Destroy a hash object.
CryptGetHashParam | Retrieve a hash object parameter.
CryptHashData | Hash a block of data, adding it to the specified hash object.
CryptHashSessionKey | Hash a session key, adding it to the specified hash object.
CryptSetHashParam | Set a hash object parameter.
CryptSignHash | Sign the specified hash object.
CryptVerifySignature | Verify a digital signature, given a handle to the hash object.


System Administration

This chapter discusses how multiple cryptographic service providers (CSP) can be installed on a computer and the default providers specified. The structure of the system registry is also mentioned.


Installing a New Provider

New providers are installed by running their Setup program. This copies the CSP files to the appropriate directories and makes all needed changes to the system registry.


Outline of CryptoAPI Registry Usage

Outline of the Microsoft CryptoAPI Registry Usage

The Microsoft® CryptoAPI uses the system registry to store a database of the CSPs that have been installed on the computer. Both the machine default providers and the user default providers are also recorded here.

Warning This section is included for informational purposes only. The details of the CryptoAPI registry usage may change at any time. Under no circumstances should an application read from or alter the registry directly.

The following is a partial outline of the portions of the system registry used by the CryptoAPI. Some sample entries are also shown.

HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Cryptography
Defaults
Provider
 Microsoft Base Cryptographic Provider v1.0
>Image Path:REG_SZ:rsabase.dll
>Signature:REG_BINARY:<digital signature>
 >Type:REG_DWORD:0x1
John's Provider
>Image Path:REG_SZ:johncsp.dll
>Signature:REG_BINARY:<digital signature>
>Type:REG_DWORD:0x2a
Provider Types
Type 001
 >Name:REG_SZ:Microsoft Base Cryptographic Provider v1.0
Type 042
 >Name:REG_SZ:John's Provider

HKEY_CURRENT_USER
Software
Microsoft
Cryptography
Providers
Type 001
>Name:REG_SZ:Microsoft Base Cryptographic Provider v1.0

Entries under the HKEY_LOCAL_MACHINE\...\Provider key contain information about all the CSPs that have been installed on the computer. These entries are created by the Setup program used to install a new CSP. Note that these entries are organized under subkeys, whose names indicate the provider name.

Entries under the HKEY_LOCAL_MACHINE\...\Provider Types key contain the name of the machine default CSP for each provider type. These entries are also created by the Setup program used to install a new CSP. Note that these entries are organized under subkeys whose names indicate the provider type (in decimal format).

Entries under the HKEY_CURRENT_USER\...\Providers key contain the name of the current user default CSP for each provider type. These entries are created or modified by the CryptSetProvider function. Note that these entries are also organized under subkeys, whose names indicate the provider type.


Microsoft Cryptographic Service Providers

The following cryptographic service providers (CSP) are currently available from Microsoft®:

The Microsoft Base Cryptographic Provider, version 2.0. The Microsoft Base Cryptographic Provider, version 2.0 provides a broad set of basic cryptographic functionalities that can be exported to other countries. It was initially distributed with the Microsoft CryptoAPI version 1.0, and is now distributed with version 2.0 for use with the Microsoft Windows NT® and Microsoft Windows® 95 operating environment.

The Microsoft Enhanced Cryptographic Provider, version 2.0. The Microsoft Enhanced Cryptographic Provider, version 2.0 provides the same capabilities as the Microsoft Base Cryptographic Provider, but provides for stronger security through longer keys and additional algorithms. It can be used with both CryptoAPI versions, but is currently available only within North America.

The Microsoft DSS Cryptographic Provider, version 1.0. The Microsoft DSS Cryptographic Provider, version 1.0 provides hashing, data signing, and signature verification capability using the Secure Hash Algorithm (SHA) and Digital Signature Standard (DSS) algorithms. It can be exported to other countries, and can be used with the Windows NT and Windows 95 operating environments.

The Microsoft Base DSS and Diffie-Hellman Cryptographic Provider, version 1.0. The Microsoft Base DSS and Diffie-Hellman Cryptographic Provider, version 1.0 is a superset of the DSS Cryptographic Provider, and supports Diffie-Hellman key exchange, hashing, data signing, and signature verification using the Secure Hash Algorithm (SHA) and Digital Signature Standard (DSS) algorithms. It can be exported to other countries, and is provided with the Windows NT and Windows 95 operating environments.

The Microsoft DSS and Diffie-Hellman/Schannel Cryptographic Provider, Version 1.0. The Microsoft DSS and Diffie-Hellman/Schannel Cryptographic Provider, version 1.0 supports hashing, data signing with DSS, generating Diffie-Hellman (D-H) keys, exchanging D-H keys, and exporting a D-H key. This CSP supports key derivation for the SSL3 and TLS1 protocols. It can be exported to other countries, and is provided with Windows NT 5.0 (or later).

The Microsoft RSA/Schannel Cryptographic Provider, Version 1.0. The Microsoft RSA/Schannel Cryptographic Provider, version 1.0 supports hashing, data signing, and signature verification. The algorithm identifier CALG_SSL3_SHAMD5 is used for SSL 3.0 and TLS 1.0 client authentication. This CSP supports key derivation for the SSL2, PCT1, SSL3 and TLS1 protocols. The hash consists of a concatenation of a MD5 hash a SHA hash and signed with a RSA private key. It can be exported to other countries, and is provided with Windows NT 5.0 (or later).


The Microsoft Base Cryptographic Provider, version 2.0

The Microsoft® Base Cryptographic Provider is a general-purpose provider that supports digital signatures and data encryption. This provider is currently included with the operating system (either Windows NT® or Windows® 95). It is also provided with Microsoft Internet Explorer, Version 3.0 or later.

The RSA public-key algorithm is used for all public-key operations.

To maintain backward compatibility with earlier versions of this provider, the name, as defined in the Wincrypt.h header file, retains the version 1.0 designation. However, version 2.0 of this provider is currently shipping. To see which version of the provider you have, make a call to CryptGetProvParam with the dwParam argument set to PP_VERSION. If 0x0200 is returned in pbData, then you have version 2.0.
Provider Type: PROV_RSA_FULL
Provider Name: MS_DEF_PROV


Base Provider Algorithms

The following table lists the algorithms supported by the Microsoft Base Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_MD2 | MD2 hashing algorithm. |
CALG_MD5 | MD5 hashing algorithm. |
CALG_SHA | SHA hashing algorithm. |
CALG_SHA1 | Same as CALG_SHA. |
CALG_MAC | MAC keyed-hash algorithm. | Block cipher MAC.
CALG_HMAC | MAC keyed-hash algorithm. | HMAC computation.
CALG_SSL3 _SHAMD5 | SLL3 client authentication algorithm. | For more information, see SSL3 Client Authentication Algorithm
CALG_RSA_SIGN | RSA public-key signature algorithm. | Key length: settable, 384 bits to 16,384 bits in 8 bit increments. Default key length: 512 bits. Signature conforms to PKCS #6.
CALG_RSA_KEYX | RSA public-key exchange algorithm. | Key length: settable, 384 bits to 512 bits in 8 bit increments. Default key length: 512 bits.
CALG_RC2 | RC2 block encryption algorithm. | Key length: 40 bits. Default mode: Cipher block chaining. Block size: 64 bits. Salt length: 88 bits.
CALG_RC4 | RC4 stream encryption algorithm. | Key length: 40 bits. Salt length: 88 bits.


The Base Provider Public-Key Blob

Public-key blobs (type PUBLICKEYBLOB) are used to store public keys. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];

The following table describes each public-key component. All values are in little-endian format.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PUBLICKEYBLOB.
rsapubkey | A RSAPUBKEY structure. The magic member should be set to "RSA1" (0x31415352) for public keys and to "RSA2" (0x32415352) for private keys. Notice that the hex values are just an ASCII encoding of "RSA1" and "RSA2."
modulus | The public-key modulus data is located directly after the RSAPUBKEY structure. The size of this data will vary, depending on the size of the public key. The number of bytes can be determined by dividing the value of RSAPUBKEY's bitlen field by eight.

Notice that public-key blobs are not encrypted, but contain public keys in plaintext form.

For more detailed information on the Base Provider key blobs, see Interoperability with RSA CSPs.


The Base Provider Private-Key Blob

Private-key blobs (type PRIVATEKEYBLOB) are used to store private keys. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];

The following table describes each private-key blob component. Note that these fields largely correspond to the ones described in section 7.2 of Public-Key Cryptography Standards (PKCS) #1.

Field | Description
blobheader | A BLOBHEADER structure as described in a previous section. The bType field must always have a value of PRIVATEKEYBLOB.
rsapubkey | An RSAPUBKEY structure as described in a previous section. The magic field must always have a value of 0x32415352 ("RSA2").
Modulus | The modulus. This has a value of "prime1 * prime2" and is often known as "n".
prime1 | Prime number 1, often known as "p".
prime2 | Prime number 2, often known as "q".
exponent1 | Exponent 1. This has a numeric value of "d mod (p - 1)".
exponent2 | Exponent 2. This has a numeric value of "d mod (q - 1)".
coefficient | Coefficient. This has a numeric value of "(inverse of q) mod p".
privateExponent | Private exponent, often known as "d".

Notice that private-key blobs are not encrypted, but contain private keys in plaintext form.

When calling CryptExportKey the developer can choose whether or not to encrypt the key. The PRIVATEKEYBLOB is encrypted if the hExpKey parameter contains a valid handle to a session key. Everything but the BLOBHEADER portion of the blob is encrypted. Note that the encryption algorithm and encryption key parameters are not stored along with the private-key blob. The application must manage and store this information. If zero is passed for hExpKey, the private key will be exported without encryption.

Warning It is very dangerous to export private keys without encryption, since they are then vulnerable to interception and use by unauthorized entities.

For more detailed information on the Base Provider's key blobs, see Interoperability with RSA CSPs.


The Base Provider Simple-Key Blob

Simple key blobs (type SIMPLEBLOB) are used to store and transport session keys. These are always encrypted with a key exchange public key. They have the following format:

BLOBHEADER blobheader;
ALG_ID algid;
BYTE encryptedkey[rsapubkey.bitlen/8];

The algorithm identifier that immediately follows the BLOBHEADER structure specifies the encryption algorithm that was used to encrypt the session key data. This typically has a value of CALG_RSA_KEYX, indicating that the session key data was encrypted with a key exchange public key, using the RSA Public-Key algorithm.

The encrypted session key data is in the form of a PKCS #1, type 2 encryption block. For details on this data format, see the Public-Key Cryptography Standards (PKCS), published by RSA Data Security, Inc.

This data is always the same size as the public key's modulus. For example, public keys generated by the Microsoft RSA Base Provider can be 512 bits (64 bytes) in length, so, in that case, the encrypted session key data is also 512 bits (64 bytes).

For more detailed information on the Base Provider's key blobs, see Interoperability with RSA CSPs.


The Microsoft Enhanced Cryptographic Provider, version 2.0

The Microsoft® Enhanced Cryptographic Provider (Enhanced Provider) supports the same capabilities as the Microsoft Base Cryptographic Provider (Base Provider), but provides for stronger security through longer keys and additional algorithms. It can be used with CryptoAPI version 1.0 and version 2.0.

Note The Enhanced Provider is currently available only within North America.

To maintain backward compatibility with earlier versions of this provider, the name, as defined in the Wincrypt.h header file, retains the version 1.0 designation. However, version 2.0 of this provider is currently shipping. To see which version of the provider you have, make a call to CryptGetProvParam with the dwParam argument set to PP_VERSION. If 0x0200 is returned in pbData, then you have version 2.0.
Provider Type: PROV_RSA_FULL
Provider Name: MS_ENHANCED_PROV

The following table shows the differences between the Base Provider, and the Enhanced Provider. The key lengths shown are the default keylengths.

Algorithm | Base Provider | Enhanced Provider
RSA public-key signature algorithm | Key length: 512 bits. | Key length: 1,024 bits.
RSA public-key exchange algorithm | Key length: 512 bits. | Key length: 1,024 bits.
RC2 block encryption algorithm | Key length: 40 bits. | Key length: 128 bits. Salt length: settable.
RC4 stream encryption algorithm | Key length: 40 bits. | Key length: 128 bits. Salt length: settable.
DES | Not supported. | Key length: 56 bits.
Triple DES (2 key) | Not supported. | Key length: 112 bits.
Triple DES (3 key) | Not supported. | Key length: 168 bits.

The Enhanced Cryptographic Provider is backward-compatible with the Base Cryptographic Provider distributed with CryptoAPI versions 1.0 and 2.0, with the following exception:

For session keys, the base provider is limited to generating and deriving RC2 or RC4 keys of default key length (40 bit for the Base Provider, and 128 bit for the Enhanced Provider). This precludes the Enhanced Provider from creating keys with Base Provider-compatible key lengths. However, the Enhanced Provider can import RC2 and RC4 keys, up to 128 bits. In other words, 40 bit keys that have been generated using the Base Provider can be imported into the Enhanced Provider and used from there.


Enhanced Provider Algorithms

The following table lists the algorithms supported by the Microsoft Enhanced Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_MD2 | MD2 hashing algorithm. |
CALG_MD5 | MD5 hashing algorithm. |
CALG_SHA | SHA hashing algorithm. |
CALG_SHA1 | Same as CALG_SHA. |
CALG_MAC | MAC keyed hash algorithm. | Block cipher MAC
CALG_HMAC | MAC keyed-hash algorithm. | HMAC computation.
CALG_SSL3 _SHAMD5 | SLL3 client authentication algorithm. | For more information, see SSL3 Client Authentication Algorithm
CALG_RSA_SIGN | RSA public-key signature algorithm. | Key length: settable, 384 bits to 16,384 bits in 8 bit increments. Default key length: 1,024 bits. Signature conforms to PKCS #6.
CALG_RSA_KEYX | RSA public-key exchange algorithm. | Key length: settable, 384 bits to 16,384 bits in 8 bit increments. Default key length: 1,024 bits.
CALG_RC2 | RC2 block encryption algorithm. | Key length: 128 bits. Default mode: Cipher block chaining. Block size: 64 bits. Salt length: settable.
CALG_RC4 | RC4 stream encryption algorithm. | Key length: 128 bits. Salt length: settable.
CALG_DES | DES encryption. | Key Length: 56 bits. Default mode: Cipher block chaining. Block size: 64 bits. No salt allowed.
CALG_3DES_112 | Two key triple DES encryption. | Key Length: 112 bits. Default mode: Cipher block chaining. Block size: 64 bits. No salt allowed.
CALG_3DES | Triple DES. | Key Length: 168 bits. Default mode: Cipher block chaining. Block size: 64 bits. No salt allowed.


The Enhanced Provider Public-Key Blob

See The Base Provider Public-Key Blob.


The Enhanced Provider Private-Key Blob

See The Base Provider Private-Key Blob.


The Microsoft DSS Cryptographic Provider, version 1.0

The Microsoft® DSS Cryptographic Provider supports hashing, data signing, and signature verification using the Secure Hash Algorithm (SHA) and Digital Signature Standard (DSS) algorithms. It can be exported to other countries, and is provided with the Windows NT and Windows 95 platforms.

Provider Type: PROV_DSS
Provider Name: MS_DEF_DSS_PROV


DSS Provider Algorithms

The following table lists the algorithms supported by the Microsoft DSS Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_MD5 | MD5 hashing algorithm. | Provided only for hashing.
CALG_SHA | SHA hashing algorithm. | Must be used for DSS signatures.
CALG_SHA1 | Same as CALG_SHA. |
CALG_DSS_SIGN | DSS public/private-key signature algorithm. | Key length: settable, 512 bits to 1,024 bits in 64 bit increments. Default key length: 1,024 bits.


The DSS Provider Public-Key Blob

When a DSS public key is exported, it is in a PUBLICKEYBLOB format, as follows:

BLOBHEADER        blobheader;
DSSPUBKEY         dsspubkey;
BYTE              p[dsspubkey.bitlen/8];
BYTE              q[20];
BYTE              g[dsspubkey.bitlen/8];
BYTE              y[dsspubkey.bitlen/8];
DSSSEED           seedstruct;

The following table describes each public key component. All values are in little-endian format.

Field | Description
blobheader | A BLOBHEADER structure The bType member must have a value of PUBLICKEYBLOB.
dsspubkey | A DSSPUBKEY structure. The magic member must have a value of 0x31535344 (the ASCII encoding of "DSS1").
p | The prime modulus P. Must always have the most significant bit of the most significant byte set to 1.
q | The prime Q - 20 bytes in length. The most significant bit of the most significant byte must be set to 1.
g | The generator G. Must be the same length as p (must be padded with 0x00 bytes if it is less).
y | The public key Y. Must be same length as p, if smaller then it must be padded with 0x00.
seedstruct | Seed and counter values for verifying primes.

Notice that public-key blobs are not encrypted, but contain public keys in plaintext form.


The DSS Provider Private-Key Blob

When a DSS private key is exported, it is in a PRIVATEKEYBLOB format, as follows:

BLOBHEADER        blobheader;
DSSPUBKEY         dsspubkey;
BYTE              p[dsspubkey.bitlen/8];
BYTE              q[20];
BYTE              g[dsspubkey.bitlen/8];
BYTE              X[20];
DSSSEED           seedstruct;

The following table describes each public-key component. All values are in little-endian format.

Field | Description
blobheader | A BLOBHEADER structure The bType member must have a value of PRIVATEKEYBLOB.
dsspubkey | A DSSPUBKEY structure. The magic member must have a value of 0x32535344 (the ASCII encoding of "DSS2").
p | The prime modulus P. Must always have the most significant bit of the most significant byte set to 1.
q | The prime Q. It is 20 bytes in length. The most significant bit of the most significant byte must be set to 1.
g | The generator G. Must be the same length as p (must be padded with 0x00 bytes if it is less).
x | The secret exponent X. It must always be 20 bytes in length. If smaller, then it must be padded with 0x00.
seedstruct | Seed and counter values for verifying primes.

When calling CryptExportKey the developer can choose whether or not to encrypt the key. The PRIVATEKEYBLOB is encrypted if the hExpKey parameter contains a valid handle to a session key. Everything but the BLOBHEADER portion of the blob is encrypted. Note that the encryption algorithm and encryption key parameters are not stored along with the private-key blob. The application must manage and store this information. If zero is passed for hExpKey, the private key will be exported without encryption.

Warning It is very dangerous to export private keys without encryption, since they are then vulnerable to interception and use by unauthorized entities.


Using the CryptoAPI with the Microsoft DSS Cryptographic Provider

The CryptoAPI can be used to hash data, generate DSS keys, sign data with DSS keys, and verify DSS signatures.


Generating and Retrieving DSS Keys

DSS Keys may be generated with a call to CryptGenKey. The call to CryptGenKey requires either AT_SIGNATURE or CALG_DSS_SIGN be passed in the Algid argument. This call will generate the P (prime modulus), Q (prime), G (generator), X (secret exponent) and Y (public key) values from scratch and persist them in a key blob to local storage. The steps necessary for this are shown in the following procedure.

To generate a DSS signature key pair
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptGenKey to generate the keys. Either AT_SIGNATURE or CALG_DSS_SIGN must be passed in for the Algid argument and the upper 16 bits of the dwFlags argument must be set to the desired key size. If the upper 16 bits are zero, then the default key size of 1,024 bits will be used. A HCRYPTKEY handle is returned in the hKey argument.
To retrieve a pointer to previously generated signature keys
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptGetUserKey, with the dwKeySpec argument set to either AT_SIGNATURE or CALG_DSS_SIGN.
To retrieve the P,Q, and G values
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptGetUserKey, with the dwKeySpec argument set to either AT_SIGNATURE or CALG_DSS_SIGN.
  3. Call CryptGetKeyParam with the hKey argument set to the pointer retrieved in the previous step. The dwParam argument must be set to the desired flag; KP_P, KP_Q, or KP_G. The value is returned in the pbData argument and the length of the data is returned in the pcbData argument. The value is returned with no header information and in little-endian format.


Generating DSS Signatures

To sign data, it must first be hashed using the SHA algorithm. Then a DSS signature is generated by calling CryptSignHash. The steps necessary for this are shown in the following procedure.

To generate a DSS signature
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptCreateHash with the Algid argument set to CALG_SHA to get a pointer to an SHA hash object.
  3. Call CryptHashData with the hHash argument set to the pointer retrieved in the previous step. This creates a hash of the data and returns a handle to the hash in the phHash argument of the CryptCreateHash function call.
  4. Call CryptSignHash with the hHash argument set to the handle retrieved in the previous step. Either AT_SIGNATURE or CALG_DSS_SIGN may be passed in the dwKeySpec parameter. The signature is returned to the address provided in the pbSignature argument and the length of the signature is returned to the address provided in the pcbSignature argument. A NULL pointer may be passed in the pbSignature argument, and in this case the signature is not generated, but the length of the signature is returned to the address provided in the pcbSignature parameter.


Verifying a DSS Signature

To verify a DSS signature, the DSS public key of the signer must be imported, the signed data must be hashed, and then the signature can be verified. The steps necessary for this are shown in the following procedure.

To verify a DSS Signature
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptImportKey to import the signer's DSS public key.
  3. Call CryptCreateHash with the Algid argument set to CALG_SHA to get a pointer to an SHA hash object.
  4. Call CryptHashData with the hHash argument set to the pointer retrieved in the previous step, and with pbData pointing to the signed data. This creates a hash of the data and returns a handle to the hash in the phHash argument of the CryptCreateHash function call.
  5. Call CryptVerifySignature with the following settings:

    hHash. set to the handle to the hash performed in the previous step.

    pbSignature. points to the signature to be verified.

    dwSigLen. set to the length of the signature.

    hPubKey. set to the handle of the public key imported in step 2.

    dwFlags. set to zero.


Exporting DSS Keys

When sending signed data to someone where the signature will need to be verified by the recipient, the signer's public key must be provided to the recipient; and is usually sent along with the signed data. Therefore, it is necessary to be able to export the DSS keys, and they are exported in a key blob format.

To export the DSS public key
  1. Call CryptAcquireContext to get a pointer to the Microsoft DSS Cryptographic Provider.
  2. Call CryptGetUserKey, with the dwKeySpec argument set to either AT_SIGNATURE or CALG_DSS_SIGN.
  3. Call CryptExportKey with hKey set to the handle retrieved in the previous step, dwBlobType set to PUBLICKEYBLOB, and dwFlags set to zero. The DSS public-key blob is returned in pbData and the length of the key blob is returned in pdwDataLen. A NULL pointer may be passed in pbData, and in this case just the length of the DSS key blob will be returned. The blob returned when making the call to CryptExportKey is in the format described in The DSS Provider Public-Key Blob.
To export the DSS private key
  1. Follow the same procedure as for exporting a DSS public key, except that when making the call to CryptExportKey, dwBlobType should be set to PRIVATEKEYBLOB. The blob returned when making the call to CryptExportKey is in the format described in The DSS Provider Private-Key Blob.


The Microsoft Base DSS and Diffie-Hellman Cryptographic Provider, Version 1.0

The Microsoft Base DSS and Diffie-Hellman Cryptographic Provider supports Diffie-Hellman (D-H) key exchange (a 40-bit DES derivative), SHA hashing, DSS data signing, and DSS signature verification. It can be exported to other countries, and is currently provided with the Microsoft® Windows NT® and Microsoft Windows® 95 platforms.

Provider Type: PROV_DSS_DH
Provider Name: MS_DEF_DSS_DH_PROV


PROV_DSS_DH Provider Algorithms

The following table lists the algorithms supported by the Microsoft Base DSS and Diffie-Hellman Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_MD5 | MD5 hashing algorithm. | Provided only for hashing.
CALG_SHA | SHA hashing algorithm. | Must be used for DSS signatures.
CALG_SHA1 | Same as CALG_SHA. |
CALG_DSS_SIGN | DSS public/private-key signature algorithm. | Key length: settable, 512 bits to 1,024 bits in 64 bit increments. Default key length: 1,024 bits.
CALG_DH_SF | Store and Forward D-H key exchange. | Key length: settable, 384 bits to 512 bits in 8 bit increments. Default key length: 512 bits.
CALG_DH_EPHEM | Ephemeral D-H key exchange. | Key length: settable, 384 bits to 512 bits in 8 bit increments. Default key length: 512 bits.
CALG_CYLINK_MEK | A 40-bit variant of a DES key. | Key Length: 40 bits.


The Diffie-Hellman Public-Key Blob

Diffie-Hellman public-key blobs (type PUBLICKEYBLOB) are used to exchange the (G^X) mod P value in a D-H key exchange. They have the following format:

BLOBHEADER blobheader; // As explained under "Data Structures"
DHPUBKEY dhpubkey;
BYTE y[dhpubkey.bitlen/8]; // Where y = (G^X) mod P

The following table describes each component of the key blob.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PUBLICKEYBLOB.
dhpubkey | A DHPUBKEY structure. The magic member should be set to "DH1" (0x31484400) for public keys. Notice that the hex value is just an ASCII encoding of "DH1."
y | The Y value, (G^X) mod P, is located directly after the DHPUBKEY structure, and should always be the length (in bytes) of the DHPUBKEY bitlen field (bit length of P) divided by eight. If the length of the data that results from the calculation of (G^X) mod P is one or more bytes shorter than P divided by 8, the data must be padded with the necessary bytes (of zero value) to make the data the desired length (little-endian format).


The PROV_DSS_DH Provider Private-Key Blob

D-H private-key blobs (type PRIVATEKEYBLOB) are used to store the public/private information of a D-H key. They have the following format:

BLOBHEADER blobheader; // As explained under "Data Structures"
DHPUBKEY dhpubkey;
BYTE prime[dhpubkey.bitlen/8];
BYTE generator[dhpubkey.bitlen/8];
BYTE secret[dhpubkey.bitlen/8];

The following table describes each component of the key blob.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PRIVATEKEYBLOB.
dhpubkey | A DHPUBKEY structure. The magic member should be set to "DH2" (0x32484400) for private keys. Notice that the hex value is just an ASCII encoding of "DH2."
prime | The prime modulus P. This data must always have the most significant bit of the most significant byte set to 1.
generator | The generator G.
secret | The secret exponent X.

Note The generator and secret must always be the same length (in bytes). If either is one byte or more shorter than the other, then it must be padded with the necessary number of bytes (of zero value) to make them the same (little-endian format).


Using the CryptoAPI with the Microsoft PROV_DSS_DH Provider

This section describes how the CryptoAPI can be used to generate D-H keys, exchange D-H keys, and export a private D-H key.

This provider can also be used to hash data, generate DSS keys, sign data with DSS keys, and verify DSS signatures. For information on how to do this, see Using the CryptoAPI with the Microsoft DSS Cryptographic Provider.


Generating Diffie-Hellman Keys

The steps necessary for this are shown in the following procedure.

To generate a Diffie-Hellman public key
  1. Get a handle to the Diffie-Hellman provider.
  2. Generate the new key. There are two ways to accomplish this — by having CryptoAPI generate all new values for G, P, and X or by using existing values for G and P, and generating a new value for X.

    To generate the key by generating all new values:

    Call CryptGenKey passing either CALG_DH_SF (store and forward) or CALG_DH_EPHEM (ephemeral) in the Algid parameter. The key will be generated, using new, random values for G and P, a newly calculated value for X, and its handle will be returned in the phKey parameter.

    The new key is now ready for use. Note that the values of G and P must be sent along with the key (or sent by some other method), when doing a key exchange.

    To generate the key by using predefined values for G and P:

    1. Initialize a CRYPT_DATA_BLOB structure with the pbData member set to the G value. It should contain no header information and should be little-endian format.
    2. Initialize a CRYPT_DATA_BLOB structure with the pbData member set to the P value. It should contain no header information and should be little-endian format.
    3. Call CryptGenKey passing either CALG_DH_SF (store and forward) or CALG_DH_EPHEM (ephemeral) in the Algid parameter, and CRYPT_PREGEN for the dwFlags parameter. A key handle will be generated and returned in the phKey parameter.
    4. The value of G may be set by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_G flag in the dwParam parameter, and a pointer to the structure containing the value of G in the pbData parameter.
    5. The value of P may be set by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_P flag in the dwParam parameter, and a pointer to the structure containing the value of P in the pbData parameter.
    6. The value of X must be generated by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_X flag in the dwParam parameter, and NULL in the pbData parameter.

      If all the function calls succeeded, the D-H public key is ready for use.

  3. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.

If CALG_DH_SF was specified in the previous procedures, the key values are persisted to storage with each call to CryptSetKeyParam. The G and P values can then be retrieved using CryptGetKeyParam. Some CSPs may have hard-coded G and P values. In this case a NTE_FIXEDPARAMETERS error will be returned if CryptSetKeyParam is called with KP_G or KP_P specified in the dwParam parameter. If CryptDestroyKey is called, the handle to the key is destroyed, but the key values are retained in the CSP. However, if CALG_DH_EPHEM was specified, the handle to the key is destroyed and all values are purged from the CSP.


Exchanging Diffie-Hellman Keys

The purpose of the Diffie-Hellman algorithm is to make it possible for two or more hosts to create and share an identical, secret encryption key by simply sharing information over an insecure network. The information that gets shared over the network is in the form of a couple of constant values, and a D-H public key. The process used by two key-exchange participants is as follows:

  • Both participants agree to the "Diffie-Hellman parameters," a prime number (P), and a base number (G).
  • Participant 1 sends its D-H public key to participant 2.
  • Participant 2 computes the secret encryption key by using the information contained in participant 1's public key.
  • Participant 2 sends participant 1 its D-H public key.
  • Participant 1 computes the secret encryption key by using the information contained in participant 2's public key.
  • Both participants now have the same encryption key, which can be used for encrypting and decrypting data. The steps necessary for this are shown in the following procedure.
To prepare a Diffie-Hellman public key for transmission
  1. Get a handle to the Diffie-Hellman provider.
  2. Get a handle to a D-H key. This can be done by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. Get the memory length (in bytes) needed to hold a D-H key by calling CryptExportKey, passing NULL for the pbData parameter. The key length will be returned in pdwDataLen.
  4. Allocate memory for the key.
  5. Create a D-H public-key blob by calling CryptExportKey, passing PUBLICKEYBLOB in the dwBlobType parameter and the handle to the D-H key in the hKey parameter. This function call causes the calculation of the public key value, (G^X) mod P. If all the preceding function calls were successful, the D-H public key is now ready to be encoded and transmitted.
To import a D-H public key and calculate the private (secret) key
  1. Get a handle to the Diffie-Hellman provider.
  2. Get a handle to a D-H key. This can be done by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. To import the key into the CSP, call CryptImportKey, passing a pointer to the public key blob in the pbData parameter, the length of the blob in the dwDataLen parameter, and the handle to the D-H key in the hPubKey parameter. This call to CryptImportKey causes the calculation, (Y^X) mod P, to be performed thus creating the shared, secret key and completing the key exchange. This function call returns a handle to the new, secret, bulk-encryption key in the hKey parameter.
  4. Convert the shared, secret key to the CALG_CYLINK_MEK, bulk-encryption key type, by calling CryptSetKeyParam with dwParam set to KP_ALGID, and with pbData set to a pointer to CALG_CYLINK_MEK. This step must be done before using the shared key in CryptEncrypt or CryptDecrypt. Calls made to either of these functions prior to calling CryptSetKeyParam will fail.

    If a call to CryptGetKeyParam is made on the key handle returned from the call to CryptImportKey and prior to calling CryptSetKeyParam (as described in this step), the ALG_ID returned by the call to CryptGetKeyParam will be CALG_AGREEDKEY_ANY. If all the preceding function calls were successful, the secret key is now ready to be used for encryption or decryption.

  5. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.


Exporting a Diffie-Hellman Private (secret) Key

The steps necessary are shown in the following procedure.

To export a D-H private key
  1. Get a handle to a D-H provider.
  2. Get a handle to a D-H key. This can be done by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. Create a D-H public-key blob by calling CryptExportKey, passing PRIVATEKEYBLOB in the dwBlobType parameter and the handle to the D-H key in the hKey parameter.
  4. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.


The Microsoft RSA/Schannel Cryptographic Provider, Version 1.0

The Microsoft® RSA/Schannel Cryptographic Provider supports hashing, data signing, and signature verification. The algorithm identifier CALG_SSL3_SHAMD5 is used for SSL 3.0 and TLS 1.0 client authentication. This CSP supports key derivation for the SSL2, PCT1, SSL3 and TLS1 protocols. The hash consists of a concatenation of a MD5 hash a SHA hash and signed with a RSA private key. It can be exported to other countries, and is provided with Microsoft® Windows NT® 5.0 (or later).

Provider Type: PROV_RSA_SCHANNEL

Provider Name: MS_DEF_RSA_SCHANNEL_PROV

For additional information about RSA/Schannel providers see RSA/Schannel CSP Overview and RSA/Schannel CSP Reference.


RSA/Schannel Provider Algorithms

The following table shows the algorithm list that might be supported by the Microsoft RSA/Schannel Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_RSA_KEYX | RSA public-key key exchange algorithm | Key length: settable, 384 bits to 16,384 bits in 8 bit increments. Default key length: 1,024 bits.
CALG_MD5 | MD5 hashing algorithm. | Provided only for hashing.
CALG_SHA | SHA hashing algorithm. | Must be used for DSS signatures.
CALG_RC2 | RC2 block encryption algorithm. | Key length: 40 to 88 bits
CALG_RC4 | RC4 stream encryption algorithm. | Key length: 40 to 88 bits


The RSA/Schannel Provider Public-Key Blob

Public-key blobs (type PUBLICKEYBLOB) are used to store public keys. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];

The following table describes each public-key components. All values are in little endian format.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PUBLICKEYBLOB.
rsapubkey | A RSAPUBKEY structure. The magic member should be set to "RSA1" (0x31415352) for public keys. Notice that the hex value is just an ASCII encoding of "RSA1."
modulus | The public-key modulus data is located directly after the RSAPUBKEY structure. The size of this data will vary, depending on the size of the public key. The number of bytes can be determined by dividing the value of RSAPUBKEY's bitlen field by eight.

Notice that public-key blobs are not encrypted, but contain public keys in plaintext form.


The RSA/Schannel Provider Private Key Blob

Private-key blobs (type PRIVATEKEYBLOB) are used to store public/private key pairs. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];

If the key blob is encrypted, then everything but the BLOBHEADER portion of the blob is encrypted. Note that the encryption algorithm and encryption key parameters are not stored along with the private key blob. It is the responsibility of the application to manage this information.

The following table describes each private-key blob components. Note that these fields largely correspond to the ones described in section 7.2 of Public-Key Cryptography Standards (PKCS) #1.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PRIVATEKEYBLOB.
rsapubkey | A RSAPUBKEY structure. The magic field must always have a value of 0x32415352 ("RSA2"). Notice that the hex value is just an ASCII encoding of "RSA2."
Modulus | The modulus. This has a value of "prime1 * prime2" and is often known as "n".
prime1 | Prime number 1, often known as "p".
prime2 | Prime number 2, often known as "q".
exponent1 | Exponent 1. This has a numeric value of "d mod (p - 1)".
exponent2 | Exponent 2. This has a numeric value of "d mod (q - 1)".
coefficient | Coefficient. This has a numeric value of "(inverse of q) mod p".
privateExponent | Private exponent, often known as "d".

Notice that private-key blobs are not encrypted, but contain private keys in plaintext form.

When calling CryptExportKey the developer can choose whether or not to encrypt the key. The PRIVATEKEYBLOB is encrypted if the hExpKey parameter contains a valid handle to a session key. Everything but the BLOBHEADER portion of the blob is encrypted. Note that the encryption algorithm and encryption key parameters are not stored along with the private-key blob. The application must manage and store this information. If zero is passed for hExpKey, the private key is exported without encryption.

Warning It is very dangerous to export private keys without encryption, since they are then vulnerable to interception and use by unauthorized entities.


The RSA/Schannel Provider Simple Key Blob

Simple key blobs (type SIMPLEBLOB) are used to store and transport session keys. These are always encrypted with a key exchange public key. They have the following format:

BLOBHEADER blobheader;
ALG_ID algid;
BYTE encryptedkey[rsapubkey.bitlen/8];

The following table describes each simple blob components. The encrypted session key data is in the form of a PKCS #1, type 2 encryption block. For details on this data format, see The Public-Key Cryptography Standards (PKCS), published by RSA Data Security, Inc.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of SIMPLEBLOB.
algid | The algorithm identifier. This typically has a value of CALG_RSA_KEYX, indicating that the session key data was encrypted with a key exchange public key, using the RSA Public-Key exchange algorithm.
encryptedkey | The encrypted session key data is in the form of a PKCS #1, type 2 encryption block. For details on this data format, see the Public-Key Cryptography Standards (PKCS), published by RSA Data Security, Inc.

This data is always the same size as the public key's modulus. For example, public keys generated by the Microsoft Base Cryptographic Provider are always 512 bits (64 bytes) in length, so the encrypted session key data is also always 64 bytes.


Using the CryptoAPI with the Microsoft MS_DEF_RSA_SCHANNEL_PROV Cryptographic Provider

The CryptoAPI can be used to hash data, generate keys, sign data, and verify signatures.


Generating And Retrieving RSA/Schannel Public/Private Keys

RSA/Schannel Keys may be generated with a call to CryptGenKey. The call to CryptGenKey requires an AT_KEYEXCHANGE algorithm identifier passed in the Algid argument.

To generate a RSA/Schannel public/private key pair
  1. Call CryptAcquireContext to get a pointer to the Microsoft RSA/Schannel Cryptographic Provider.
  2. Call CryptGenKey to generate the keys. AT_KEYEXCHANGE must be passed in for the Algid argument and the upper 16 bits of the dwFlags argument must be set to the desired key size (512 bits). A HCRYPTKEY handle is returned in the hKey argument.
To retrieve a pointer to previously generated RSA/Schannel user keys
  1. Call CryptAcquireContext to get a pointer to the Microsoft RSA/Schannel Cryptographic Provider.
  2. Call CryptGetUserKey, with the dwKeySpec argument set to AT_KEYEXCHANGE.


Exporting RSA/Schannel Keys

Master keys can be exported into SIMPLEBLOBs. This should be implemented the same way as the export of normal bulk encryption keys, such as RC4 or DES. The aiKeyAlg field of the BLOBHEADER structure should be set to the algorithm identifier of the master key (CALG_PCT1_MASTER, CALG_SSL2_MASTER, CALG_SSL3_MASTER, or CALG_TLS1_MASTER).

If the CPExportKey function is being used to export an SSL2 master key and the CRYPT_SSL2_SLUMMING flag is set, then the first 8 bytes of the encryption block padding should be set to 0x03 rather than to random data. This helps prevent version rollback attacks, and is discussed in the SSL3 specification.

If the CRYPT_DESTROYKEY flag is specified with the CPExportKey function, then the CSP should destroy the key (or the key handle) after exporting the key. This flag is intended for use only with opaque blobs. See the The Opaque Blob Type section.


The Microsoft DSS and Diffie-Hellman/Schannel Cryptographic Provider, Version 1.0

The Microsoft® DSS and Diffie-Hellman/Schannel Cryptographic Provider supports hashing, data signing with DSS, generating Diffie-Hellman (D-H) keys, exchanging D-H keys, and exporting a D-H key. This CSP supports key derivation for the SSL3 and TLS1 protocols. It can be exported to other countries, and is provided with Microsoft® Windows NT® 5.0 (or later).

Provider Type: PROV_DH_SCHANNEL

Provider Name: MS_DEF_DH_SCHANNEL_PROV

For additional information on Diffie-Hellman/Schannel providers see Diffie-Hellman/Schannel CSP Overview and Diffie-Hellman/Schannel CSP Reference.


Diffie-Hellman/Schannel Provider Algorithms

The purpose of the Diffie-Hellman algorithm is to make it possible for two or more hosts to create and share an identical, secret encryption key, by simply sharing information over an insecure network. The information that gets shared over the network is in the form of a couple of constant values, and a D-H public key.

The following table shows the algorithm list supported by the Microsoft Diffie-Hellman/Schannel Cryptographic Provider:

Algorithm ID | Description | Comments
CALG_DH_SF | Diffie-Hellman store and forward key exchange algorithm | Key length: settable, 384 bits to 512 bits in 8 bit increments. Default key length: 512 bits.
CALG_MD5 | MD5 hashing algorithm. | Provided only for hashing.
CALG_DH_EPHEM | Ephemeral D-H key exchange. | Key length: settable, 384 bits to 512 bits in 8 bit increments. Default key length: 512 bits.
CALG_SHA | SHA hashing algorithm. | Must be used for DSS signatures.
CALG_RC2 | RC2 block encryption algorithm | Key length 40 to 88 bits.
CALG_RC4 | RC4 stream encryption algorithm | Key length: 40 to 88 bits.
CALG_CYLINK_ MEK | DES variant encryption algorithm | Key length: 40 bits.


The Diffie-Hellman/Schannel Provider Public-Key Blob

D-H public-key blobs (type PUBLICKEYBLOB) are used to exchange the (G^X) mod P value in a D-H key exchange. They have the following format:

BLOBHEADER blobheader;
DHPUBKEY dhpubkey;
BYTE y[dhpubkey.bitlen/8]; // Where y = (G^X) mod P

The following table describes each component of the key blob.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PUBLICKEYBLOB.
dhpubkey | A DHPUBKEY structure. The magic member should be set to "DH1" (0x31484400) for public keys. Notice that the hex value is just an ASCII encoding of "DH1."
y | The y value, (G^X) mod P, is located directly after the DHPUBKEY structure, and should always be the length (in bytes) of DHPUBKEY's bitlen field (bit length of P) divided by eight. If the length of the data that results from the calculation of (G^X) mod P is one or more bytes shorter than P divided by 8, the data must be padded with the necessary bytes (of zero value) to make the data the desired length (little endian format).


The Diffie-Hellman/Schannel Provider Private Key Blob

D-H private-key blobs (type PRIVATEKEYBLOB) are used to store the public/private information of a D-H key. They have the following format:

BLOBHEADER blobheader;
DHPUBKEY dhpubkey;
BYTE prime[dhpubkey.bitlen/8];
BYTE generator[dhpubkey.bitlen/8];
BYTE secret[dhpubkey.bitlen/8];

The following table describes each component of the key blob.

Field | Description
blobheader | A BLOBHEADER structure. The bType member must have a value of PRIVATEKEYBLOB.
dhpubkey | A DHPUBKEY structure. The magic member should be set to "DH2" (0x32484400) for private keys. Notice that the hex value is just an ASCII encoding of "DH2."
prime | The prime modulus P. This data must always have the most significant bit of the most significant byte set to 1.
generator | The generator G. See note 1.
secret | The secret exponent X. See note 1.

Note The prime, generator and secret must always be the same length (in bytes). If any component is one byte or more shorter than the other, then it must be padded with the necessary number of bytes (of zero value) to make them the same (little endian format).


Using the CryptoAPI with the Microsoft MS_DEF_DH_SCHANNEL_PROV Cryptographic Provider

This section describes how the CryptoAPI can be used to generate D-H keys, exchange D-H keys, and export a private D-H key.


Generating Diffie-Hellman/Schannel Keys

To generate a Diffie-Hellman public key
  1. Get a handle to the Diffie-Hellman provider.
  2. Generate the new key. There are two ways to accomplish this, by having CryptoAPI generate new values for G, P, and X, or by using existing values for G and P, and generating a new value for X.

    To generate the key by generating all new values:

    Call CryptGenKey passing either CALG_DH_SF (store and forward) or CALG_DH_EPHEM (ephemeral) in the Algid parameter. The key will be generated, using new, random values for G and P, a newly calculated value for X, and its handle will be returned in the phKey parameter.

    The new key is now ready for use. Note that the values of G and P must be sent along with the key (or sent by some other method), when doing a key exchange.

    To generate the key by using predefined values for G and P:

    1. Initialize a CRYPT_DATA_BLOB structure with the pbData member set to the G value. It should contain no header information and should be little endian format.
    2. Initialize a CRYPT_DATA_BLOB structure with the pbData member set to the P value. It should contain no header information and should be little endian format.
    3. Call CryptGenKey passing either CALG_DH_SF (store and forward) or CALG_DH_EPHEM (ephemeral) in the Algid parameter, and CRYPT_PREGEN for the dwFlags parameter. A key handle will be generated and returned in the phKey parameter.
    4. The value of G may be set by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_G flag in the dwParam parameter, and a pointer to the structure containing the value of G in the pbData parameter.
    5. The value of P may be set by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_P flag in the dwParam parameter, and a pointer to the structure containing the value of P in the pbData parameter.
    6. The value of X must be generated by calling CryptSetKeyParam, passing the key handle (retrieved in step c) in the hKey parameter, the KP_X flag in the dwParam parameter, and NULL in the pbData parameter.

      If all the function calls succeeded, the D-H public key is ready for use.

  3. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.

If CALG_DH_SF was specified in the previous procedures, the key values are persisted to storage with each call to CryptSetKeyParam. The G and P values can then be retrieved using CryptGetKeyParam. Some CSPs may have hard coded G and P values. In this case a NTE_FIXEDPARAMETERS error will be returned if CryptSetKeyParam is called with KP_G or KP_P specified in the dwParam parameter. If CryptDestroyKey is called, the handle to the key is destroyed, but the key values are retained in the CSP. However, if CALG_DH_EPHEM was specified, the handle to the key is destroyed and all values are purged from the CSP.


Exchanging Diffie-Hellman/Schannel Keys

The Diffie-Hellman algorithm makes it possible for two or more hosts to create and share an identical, secret encryption key, by simply sharing information over an insecure network. The information shared over the network is in the form of a couple of constant values and a D-H public key. The process used by two key-exchange participants is as follows:

  • Both participants agree to the "Diffie-Hellman parameters"; a prime number, P and a base number, G.
  • Participant 1 sends its D-H public key to participant 2.
  • Participant 2 computes the secret encryption key by using the information contained in Participant 1's public key.
  • Participant 2 sends Participant 1 its D-H public key.
  • Participant 1 computes the secret encryption key by using the information contained in Participant 2's public key.
  • Both participants now have the same encryption key, which can be used for encrypting and decrypting data.
To prepare a Diffie-Hellman/Schannel public key for transmission
  1. Get a handle to the Diffie-Hellman provider. Do this by calling CryptAcquireContext to get a pointer to the Microsoft DH Schannel Cryptographic Provider.
  2. Get a handle to a D-H key. Do this by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. Get the memory length (in bytes) needed to hold a D-H key by calling CryptExportKey, passing NULL for the pbData parameter. The key length will be returned in pcbData.
  4. Allocate memory for the key.
  5. Create a D-H public-key blob by calling CryptExportKey, passing PUBLICKEYBLOB in the dwBlobType parameter and the handle to the D-H key in the hKey parameter. This function call calculates the public key value, (G^X) mod P. If all the preceding function calls were successful, the D-H public key is now ready to be encoded and transmitted.
To import a Diffie-Hellman/Schannel public key and calculate the agreed (secret) key
  1. Get a handle to the Diffie-Hellman provider. Do this by calling CryptAcquireContext to get a pointer to the Microsoft DH Schannel Cryptographic Provider.
  2. Get a handle to a D-H key. Do this by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. To import the key into the CSP, call CryptImportKey, passing a pointer to the public key blob in the pbData parameter, the length of the blob in the dwDataLen parameter, and the handle to the D-H key in the hImpKey parameter. This call to CryptImportKey causes the calculation, (Y^X) mod P, to be performed thus creating the shared, secret key and completing the key exchange. This function call returns a handle to the new, secret, bulk-encryption key in the hKey parameter.
  4. Convert the shared, secret key to the appropriate ALG_ID, bulk-encryption key type, by calling CryptSetKeyParam with dwParam set to KP_ALGID (See CPSetKeyParam Diffie-Hellman/Schannel Extensions), and with pbData set to a pointer to CALG_CYLINK_MEK. This step must be done before using the shared key in CryptEncrypt or CryptDecrypt. Calls made to either of these functions prior to calling CryptSetKeyParam will fail.

    If a call to CryptGetKeyParam is made on the key handle returned from the call to CryptImportKey and prior to calling CryptSetKeyParam (as described in this step), the ALG_ID returned by the call to CryptGetKeyParam will be CALG_AGREEDKEY_ANY. If all the preceding function calls were successful, the agreed key is now ready to be used for encryption or decryption.

    The SSL 3.0 or TLS 1.0 key length is 48 bytes. To obtain the required length, take the 384 Least Significant Bits of the returned HCRYPTKEY for this agreed key.

  5. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.


Exporting a Diffie-Hellman/Schannel Agreed (secret) Key

To export a Diffie-Hellman/Schannel agreed key
  1. Get a handle to a D-H provider. Do this by calling CryptAcquireContext to get a pointer to the Microsoft DH Schannel Cryptographic Provider.
  2. Get a handle to a D-H key. Do this by calling CryptGenKey (see Generating Diffie-Hellman Keys) to create a new key, or by calling CryptGetUserKey to retrieve an existing one.
  3. Create a D-H public-key blob by calling CryptExportKey, passing PRIVATEKEYBLOB in the dwBlobType parameter and the handle to the D-H key in the hKey parameter.
  4. When finished with the key, call CryptDestroyKey to destroy the handle (HCRYPTKEY) to the key.


Encoding and Decoding Data

In order for data to be sent over a serial line, such as a phone line, the data must be serialized. That is, the data must be converted to a string of ones and zeros that are transmitted serially over the line. This must be done in a manner such that the computer receiving the data can deserialize the data back into its original format. The exact manner in which this is accomplished is called a communication protocol, and is controlled by both software and data-transmission hardware. There are several levels at which the data is converted. The following illustration shows a greatly simplified view of communication protocol layers.

As shown in the accompanying illustration, an application, the Application Layer on Computer #1, sends the data to be transmitted (usually consisting of some combination of textual characters and numbers) to the Encoding/Decoding Layer, where the data is encoded into a stream of computer bytes. At the lowest level, the Hardware Layer, the hardware converts the bytes of data into a serial stream of ones and zeros that is transmitted over the line to Computer #2. The Hardware Layer of Computer #2 converts the ones and zeros back into computer bytes, and passes them up to the Encode/Decode Layer for decoding. The Encode/Decode Layer decodes the bytes back into their original format and passes the data up to the Application Layer. In reality, there are generally more layers involved in a given protocol, but this simplified view is adequate for the purposes of this discussion.

An accepted software design principle involves the use of abstraction, the process of describing a problem or object in terms of its general parameters rather than describing all the details necessary to solve the problem, or describing all the details of an object. Using abstraction, a designer can specify a software object that has specific qualities without concern for how the object is actually implemented in the software code. Such a practice leaves the implementation open; it simplifies the specification; and it makes it possible to state axioms about the object that can be proved when the object is implemented, and that can be assumed when the object is employed in another, higher-level object. Abstraction is the hallmark of most modern software specifications.

Most communication protocols involve a good deal of abstraction. Objects at higher layers are defined abstractly and are intended to be implemented by using objects at lower layers. For instance, a service at one layer may require the transfer of certain abstract objects between computers; a lower layer may provide transfer services for strings of ones and zeroes, using encoding rules to transform the abstract objects into such strings.

One common method of specifying abstract objects that are intended to be serially transmitted is called Abstract Syntax Notation One (ASN.1), and is defined in CCITT Recommendation X.208. One set of rules for representing such objects as strings of ones and zeros is called the Distinguished Encoding Rules (DER), and is defined in CCITT Recommendation X.509, Section 8.7. These are the encoding methods currently used by the CryptoAPI.


Introduction to Abstract Syntax Notation One (ASN.1)

The CryptoAPI does not require that the application programmer use ASN.1 notation (language) to encode and decode data. However, it is recommended that a programmer become generally familiar with ASN.1 notation because the C structures used by the CryptoAPI to encode and decode data mirror the appropriate ASN.1 data types.

A very brief overview of ASN.1 is presented in this section. The article A Layman's Guide to a Subset of ASN.1, BER, and DER, by RSA Data Security, Inc., is recommended as additional reading on this subject, and can be found at http://www.rsa.com/rsalabs/pubs/PKCS.

ASN.1 is a flexible, abstraction notation that allows a variety of data types to be defined, from simple types such as integers and bit strings, to structured types such as collections of one or more other types.

The DER is a set of rules that define how the ASN.1 abstractions get serialized into streams of ones and zeros for transmission over the line. The DER describes how to represent or encode values of each ASN.1 data type as a string of eight-bit bytes (also referred to as octets).

In ASN.1, a type is a set of values. For some types, there are a finite number of values, and for other types there are an infinite number. A value of a given ASN.1 type is an element of the type's set. ASN.1 has four kinds of types:

  • Simple types, which are base types and have no components.
  • Structured types, which have components
  • Tagged types, which are derived from other types.
  • Other types, which include the CHOICE type and the ANY type.

Types and values can be given names with the ASN.1 assignment operator (::=), and those names can be used in defining other types and values. Only the first two types will be reviewed in this document. Information on the other types can be found in A Layman's Guide to a Subset of ASN.1, BER, and DER, by RSA Data Security, Inc.

ASN.1 Simple Types

Simple types are the base types, and do not have components. ASN.1 defines several of these simple types. The types that are relevant to the Public Key Cryptography Standards (PKCS) are the following:

  • BIT STRING - an arbitrary string of bits (ones and zeroes).
  • IA5String - an arbitrary string of IA5 (ASCII) characters.
  • INTEGER - an arbitrary integer.
  • NULL - a null value.
  • OBJECT IDENTIFIER - an object identifier, which is a sequence of integer components that identify an object such as an algorithm or attribute type.
  • OCTET STRING - an arbitrary string of octets (eight-bit values).
  • PrintableString - an arbitrary string of printable characters.
  • T61String - an arbitrary string of T.61 (eight-bit) characters.
  • UTCTime - a "coordinated universal time" or Greenwich Mean Time (GMT) value.

ASN.1 Structured Types

Structured types are those consisting of components. ASN.1 defines four structured types, all of which are relevant to PKCS:

  • SEQUENCE - an ordered collection of one or more types.
  • SEQUENCE OF - an ordered collection of zero or more occurrences of a given type.
  • SET - an unordered collection of one or more types.
  • SET OF - an unordered collection of zero or more occurrences of a given type.

The structured types can have optional components, possibly with default values.

Example ASN.1 Notation

An example abstraction that uses ASN.1 notation to define certificate request information, is as follows:

CertificationRequestInfo:
CertificationRequestInfo ::= SEQUENCE {
  version Version,
  subject Name,
  subjectPublicKeyInfo SubjectPublicKeyInfo,
  attributes [0] IMPLICIT Attributes }
Version ::= INTEGER
Attributes ::= SET OF Attribute

In the preceding example, a CertificationRequestInfo object is created and assigned to be a SEQUENCE. This particular sequence includes the following set of values:

Identifier | Type Reference
version | Version
subject | Name
subjectPublicKeyInfo | SubjectPublicKeyInfo
attributes [0] | IMPLICIT Attributes

Notice that the Version type is assigned as an integer, and the Attributes type is assigned to be a SET OF Attribute types.

Additional information on certification request information can be found in the the RSA Laboratories Technical Note, PKCS #10: Certification Request Syntax Standard, by RSA Data Security, Inc., which can be found at http://www.rsa.com.

The next section describes how the CryptoAPI deals with the ASN.1 CertificationRequestInfo abstraction.


Encoding and Decoding With the CryptoAPI

The CryptoAPI has been designed to relieve the programmer from having to actually perform the ASN.1 encoding. Message functions are provided that encode and decode Public Key Cryptography Standard (PKCS) #7 messages where the actual encoding and decoding are handled by the function itself. For additional information on message functions, see Using Low-Level Message Functions, Using Simplified Message Functions, Low-Level Message Functions, and Simplified Message Functions.

For those occasions where the message functions aren't appropriate, such as when encoding certificate requests, the CryptoAPI provides two other functions to aid the programmer with encoding and decoding; CryptEncodeObject and CryptDecodeObject. These functions are designed to use C structures that mirror the appropriate ASN.1 SEQUENCE. This way, the programmer can deal with the familiar C structure rather than having to deal with the ASN.1 encoding language. For example, the ASN.1 abstraction for certificate request information (reviewed in the previous section) is:

CertificationRequestInfo:
CertificationRequestInfo ::= SEQUENCE {
  version Version,
  subject Name,
  subjectPublicKeyInfo SubjectPublicKeyInfo,
  attributes [0] IMPLICIT Attributes }
Version ::= INTEGER
Attributes ::= SET OF Attribute

The CryptoAPI C structure used to represent this ASN.1 abstraction is:

typedef struct _CERT_REQUEST_INFO {
    DWORD                 dwVersion;
    CERT_NAME_BLOB        Subject;
    CERT_PUBLIC_KEY_INFO  SubjectPublicKeyInfo;
    DWORD                 cAttribute;
    PCRYPT_ATTRIBUTE      rgAttribute;
} CERT_REQUEST_INFO,     *PCERT_REQUEST_INFO;

Notice the following similarities and differences between the ASN.1 notation and the C structure:

ASN.1 Value ID | ASN.1 Type | Struct Member ID | Struct Type
version | INTEGER | dwVersion | DWORD
subject | Name | Subject | CERT_NAME _BLOB
subjectPublic KeyInfo | SubjectPublicKey Info | SubjectPublicKey Info | CERT_PUBLIC _KEY_INFO
 |  | cAttribute | DWORD
attributes | IMPLICIT Attributes | rgAttribute | PCRYPT _ATTRIBUTE

The structure ID that gets passed into the function along with the structure determines the type of processing performed by the function. The run-time code necessary to perform the DER encoding of the items listed in the table in CryptEncodeObject/CryptDecodeObject Functions is supplied with the CryptoAPI. However, if you want to extend the ability of the CryptoAPI to encode data not defined in that table, a DER encoding compiler, such as the one produced by Open Systems Solutions, Inc. (OSS), will be required. Additional information on extending the performance of the CryptoAPI can be found in Extending CryptoAPI Functionality.

For a description of the general model these functions follow, see the General Encode/Decode Model and Using the Encode/Decode Functions.


The General Encode/Decode Model

The encoding process involves encoding nested C structures. First, the lowest level structure must be encoded. This is depicted as Structure 3 in the following illustration. To do this, the CryptEncodeObject function can be called with Structure 3 as its input, and its output will be a blob with the input information encoded and provided as a member of Structure 2. This process is repeated until the final encoded certificate (blob) is output from the function call.

The decoding process is just the opposite of the encoding process and involves taking an encoded certificate, usually in the form of a blob of bits, and decoding it into various predefined C structures. The following illustration depicts the decoding process.

The process starts with the encoded certificate, an encoded blob (it also has a C structure encoded with it, which for the sake of clarity, is not shown here). When the CryptDecodeObject function is run on this blob, the output from it is a C structure that has both usable (nonencoded) members, and encoded members that need further decoding. This is depicted as C structure 1 in the following illustration. If structure 1 is used as the input to the CryptDecodeObject function, the encoded members are decoded and output as structure 2. This will most likely still have encoded members, and the process must be run another time or two until all the members have been fully decoded (depicted as structure 3).


Using the Encode/Decode Functions

The CryptEncodeObject and CryptDecodeObject functions can be used for encoding and decoding certificates, certificate extensions, certificate requests, certificate revocation lists, and certificate trust lists, to mention just a few. For a complete list of structures that can be encoded and decoded, see CryptEncodeObject/CryptDecodeObject Functions.

Two examples for using these functions are provided:

Certificates. For details on how to use CryptEncodeObject and CryptDecodeObject to encode and decode a certificate, see Certificate Encoding/Decoding.

Certificate requests. For details on how to use CryptEncodeObject to encode a certificate request, see Creating Certificate Requests, and Certificate Request Example Code.


Authentication Using Certificates

As mentioned earlier in the overview chapter, authentication is very crucial to secure communications. You must know that the entity with whom you are communicating is, in fact, who it claims to be. The use of certificates is a common way of authenticating the person or entity with whom you want to communicate. This section will provide an overview of how certificates may be used for secure communications and how to use the Microsoft® CryptoAPI to manage and use those certificates.


Digital Certificates--An Overview

Digital Certificates—An Overview

The use of some form of physical documentation to achieve authentication has been in existence for a long time. For example, when you write a check and the merchant asks to see your driver's license, the license is being used to increase the merchant's confidence that you are who the check indicates you are. In this case the merchant trusts that the state that issued you the license did an adequate job of verifying your identity. Another example is your use of a passport when traveling. The customs official who looks at your passport and then accepts it as proof that you are who you say you are trusts that your government did an adequate job of identifying you before issuing you a passport. Notice that in both examples there has to be a level of trust in the certifying authority.

This same concept has been applied to the authentication of persons and entities on a digital communications network. The documents that provide authentication of persons and entities on a network are called digital certificates, commonly shortened to just certificates. Using certificates on a network is more complex because of the fact that the communicating parties will most likely never physically meet—so, a method must be worked out to maintain the necessary level of trust. Additionally, it is much easier on a network for unethical people to intercept messages and pretend to be someone who they are not. To prevent these kinds of problems, cryptographic techniques are used on a certificate to make it very difficult, if not impossible, for someone to modify it such that he or she can impersonate someone else.

Digital certificates have one other unique characteristic. They contain the public key of the person or entity to whom the certificate is issued. For more information on the use of public-key cryptography see Generating Cryptographic Keys.


The Hierarchy of Trust

As mentioned in the previous section, in order for digital certificates to be effective, the users of the network must have a high level of trust in the certificate. But what happens if someone doesn't trust the Certification Authority (CA)—perhaps the person has never heard of the CA before, and therefore is uncomfortable with accepting the certificate at face value? This problem is addressed in the certifying process, by something called the hierarchy of trust.

The concept of hierarchy of trust is simply that the process must begin with some certifying authority that everyone agrees is trustworthy. Perhaps this could be some agency of the federal government, such as the U.S. Postal Service, or some company that everyone agrees is trustworthy. This ultimate authority, whatever it is, is called the root authority. The root authority can then certify other, first-tier CAs, who can then certify second tier CAs, as shown in the following illustration.

When a certificate that has been issued by a tier 1 or tier 2 CA is received by someone on the network, that person can verify that the CA that signed the certificate has been certified by the level above it, and that the one at that level has been certified by the one above it, until it is determined that a chain of trust exists between the lower level CA and the root CA. For example, in the preceding diagram, it could be verified that CA #4 was certified by CA #1 and that CA #1 was certified by the root CA. This means that when a certificate from a lower-level CA is passed along with the encrypted message, all of the certificates in its chain of trust up to the root should be passed along with it.

It should be noted that the diagram and description just presented is conceptual, and that in the real world the situation is rapidly evolving, with no single root authority having been established or accepted. It appears that, for the short term, it may be that islands of authority will develop as shown in the following illustration.

As time passes, it is possible that the root islands (Root 1 and Root 2 in the illustration) could become Tier 1 CAs to a single root CA. At that point, the situation would again have a single root authority, as shown in the illustration earlier in this topic. It remains to be seen just how the actual picture is going to evolve.


Digital Certification

One of the primary goals of a digital certificate is to confirm that the public key contained in the certificate is, in fact, the public key belonging to the person or entity to whom the certificate is issued. For example, a CA may digitally sign a special message (the certificate information) containing the name of some user, say "Alice," and her public key. This is done in such a way that anyone can verify that the certificate information message was signed by no one other than the CA, and thereby develop trust in Alice's public key.

The typical implementation of digital certification involves a signature algorithm for signing the certificate. The process goes something like this:

  1. Alice sends a signed certification request containing her name and her public key to a CA.
  2. The CA creates a special message, m, from Alice's request and signs it with its private key, obtaining a separate signature, sig, in the process. The CA returns the message, m, and the signature, sig, to Alice. The two parts together form a certificate.
  3. Alice sends the certificate to Bob to convey trust in her public key.
  4. Bob verifies the signature, sig, by using the CA's public key. If the signature proves valid, he accepts Alice's public key.

As with an ordinary digital signature, anyone can verify, at any time, that the certificate was signed by the CA, without access to any secret information.

The scenario just presented assumes that Bob knows the CA's public key. That key could be obtained by getting a copy of the CA's certificate, which contains its public key.

A broader application of digital certification produces a certificate that includes not only Alice's name and public key, but also other information about Alice. Such a certificate is usually called an extended certificate. Extended certificates are more than stepping stones in a digital hierarchy of trust. They enable the CA to give Bob a means of trusting not only Alice's public key, but also that other information. The other information may include, for example, Alice's e-mail address, her authorization to sign documents of a given value, or her authorization to sign other certificates.

Because certificates have a valid time duration, it is possible for the certificate to expire and no longer be valid. It is also possible for certificates to be revoked by the CA for other reasons. To handle this situation, the CA maintains a list of revoked certificates. This list is called a certificate revocation list (CRL), and it is made available to users of the network, so that they can determine the validity of any given certificate.


Certificates and the CryptoAPI

The CryptoAPI supports the use of certificates, as defined in the ITU-T recommendation X.509 (also, ISO/IEC 9594-8). The following information is contained in a standard X.509 certificate.

Field | Description
Version | Version number of the certificate.
Serial Number | Serial number of the certificate.
Algorithm Identifier | Signature algorithm used by the certificate signer.
Issuer Name | Name of the issuer of the certificate.
Validity: | The time period over which the certificate is valid:
Not Before (Date) | Not before date.
Not After (Date) | Not after date.
Subject Name | Name of the person or entity to whom the certificate is being issued.
Subject Public Key Info: | Information about the subject's public key:
Algorithm | The algorithm used for the public key.
Subject Public Key | The actual public key (a bit string).
Optional Fields: | Optional fields:
Issuer Unique ID | If present, version must be version 2.
Subject Unique ID | If present, version must be version 2.
Extensions | Optional field. Represents additional data that an issuer may want to add to a certificate; such as, e-mail address or authorization to issue certificates. If present, version must be version 3.

The CryptoAPI provides functions with which you can extract the desired information contained in a certificate. For the syntax of these functions see Certificate Store Functions and Certificate Helper Functions.

Over a period of time, it is not unusual for certificates to accumulate on a user's computer. It is imperative that the user have the necessary tools to manage these certificates. The CryptoAPI provides those tools in the form of API functions that allow you to store, retrieve, delete, list (enumerate), and verify certificates. It also provides the means to attach certificates to messages that are being sent.


Managing Certificates

This section discusses using Microsoft® CryptoAPI functions to manage certificates. Two main categories of functions are available to manage certificates: those that manage certificate stores, and those that assist using certificates with messages. The functions that manage certificate stores include functions for working with logical or virtual stores, remote stores, external stores, and relocatable stores. These advanced concepts are discussed at the end of the section.


Certificate Store Concepts

Certificates, certificate revocation lists (CRLs), and certificate trust lists (CTLs) are kept and maintained in a certificate store, and can be retrieved for use in authentication processes. Throughout this section, all references to certificates, unless otherwise noted, should be taken to include certificates, CRLs, and CTLs. A typical certificate store is a linked list of certificates as shown in the following diagram.

The previous illustration shows:

  • Each certificate store has a pointer to the first certificate block in that store.
  • A certificate block includes a pointer to that certificate's data and a 'next' pointer to the next certificate block in the store.
  • The 'next' pointer in the last certificate block is set to NULL.
  • The data block of a certificate contains the read only certificate context and any extended properties of the certificate.
  • The data block of each certificate contains a reference count that keeps track of the number of pointers to the certificate that exist.

The certificates in a certificate store are normally kept in some kind of permanent storage such as a disk file or the system registry. Certificate stores can also be created and opened strictly in memory. This might be done to create temporary certificate storage while working with a group of certificates that does not need to be put into permanent storage. Additional store locations have been added to allow stores to be kept and searched in various parts of a local computer's registry or, with proper permissions set, in the registry on a remote computer.

Each user has a MY certificate store where that user's personal certificates and those certificates that the user most frequently uses may be kept. The MY store is currently persisted to a registry sub-key.

The use of certificates for authentication depends on having certificates that have been issued by some trusted certificate issuer. Certificates for the most trusted issuers that can be used to authenticate newly received certificates are normally kept in the ROOT store which is predefined and currently persisted to a registry sub-key. In CryptoAPI, the root store's contents are protected and special user interface (UI) controls the certificates that are added to the ROOT store. In enterprise network situations, the domain controller computer might copy most trusted issuer certificates to the ROOT stores of all its client computers.

Infrequently used certificates that should not be stored in the ROOT store may be stored in the certification authority (CA) store.

The certificate store is central to all certificate functionality. The certificates are managed in the store by using functions with a "Cert" prefix. For example code using some of these functions, see Example Code for Fundamental Certificate Store Operations.


Opening a Certificate Store

To gain access to certificates the certificate store in which they are stored must be opened through a call to CertOpenStore.

Usually, a certificate store is opened in cached memory. It may be a new store or its contents may be loaded from the local registry, the registry on a remote computer, a disk file, a PKCS #7 message, or some other source.

CryptoAPI certificate store functions also allow a store to maintain certificates outside of cached memory in, for example, an external database of certificates such as the one provided by the Microsoft® Certificate Server Database.

The lpszStoreProvider parameter of the CertOpenStore function determines the type of store opened and the provider used to open that store. Example Code for Opening a Certificate Store provides examples of opening certificate stores using various providers.


Closing a Certificate Store

CertCloseStore closes a certificate store.

When a certificate store is closed, each of the certificate contexts in that store has its reference count reduced by one. Memory is automatically freed for certificates whose reference count goes to zero.

Setting CERT_CLOSE_STORE_FORCE_FLAG with CertCloseStore closes the certificate store and frees all of its certificate contexts regardless of their reference count. In some cases, such as in multithreaded programs, this may not be desirable. If CERT_CLOSE_STORE_CHECK_FLAG is set, the store is closed, but a warning value is returned by the function if memory is still allocated for certificates whose reference counts have not been reduced to zero. If a certificates reference count is greater than zero, one or more duplicates of that certificate contexts have not been freed. Use CertFreeCertificateContext, CertFreeCRLContext, and CertFreeCTLContext to free any certificates left open.

Note A certificate context is a data structure of type CERT_CONTEXT that has, among other members, a pointer to the encoded certificate blob and a pointer to a CERT_INFO data structure. The CERT_INFO structure contains the most significant certificate data. For more information about certificate, CRL and CTL context data structures, see Certificate Encoding/Decoding.

Each certificate context also contains a reference count indicating the number of copies of the context's address that have been assigned. Each time a certificate context is duplicated, its reference count in incremented by one. Each time a pointer to a certificate context is freed, the reference count in the certificate context is decremented by one. When the reference count on a certificate context reaches zero, the memory holding the context is de-allocated. Memory allocated for a certificate context is also de-allocated when that context is in a store and the store is closed using CERT_CLOSE_STORE_FORCE_FLAG. If the memory for a context is de-allocated and pointers to that context are still in use, those pointers become invalid.


Adding Certificates

Several functions add certificates to a store. Three of them, CertAddCertificateContextToStore, CertAddCRLContextToStore, and CertAddCTLContextToStore add certificates that are already in context form. CertAddEncodedCertificateToStore, CertAddEncodedCRLToStore, and CertAddEncodedCTLToStore, add certificates that start out only in encoded form.

For more information on encoding and decoding, see Certificate Encoding/Decoding.


Retrieving Certificates

Two functions retrieve certificates from a store. CertGetIssuerCertificateFromStore retrieves a certificate based on its issuer. If both the issuer and serial number are known, use CertGetSubjectCertificateFromStore.

CertGetCRLFromStore retrieves CRL from a store.

CertVerifySubjectCertificateContext performs enabled verification checks on the subject certificate using the issuer certificate.


Adding and Retrieving Certificate Properties

Several functions add extended properties to certificates. The original data in a certificate context is read-only and cannot be changed; however, CryptoAPI certificates also have dynamic extended properties that can be added and changed. These properties include data that:

  • Pertain to the private key to be used with the certificate.
  • Indicate the type of hashes to be performed on the certificate.
  • Provide user-defined information associated with the certificate.

Values for these properties are attached to and move with the certificate. There are currently five predefined properties identified with property IDs:

  • CERT_KEY_PROV_HANDLE_PROP_ID, CERT_KEY_PROV_INFO_PROP_ID, and CERT_KEY_CONTEXT_PROP_ID

    These properties tie a certificate to a particular CSP (Certificate Service Provider) and, within that CSP, to a particular private key.

  • CERT_SHA1_HASH_PROP_ID and CERT_MD5_HASH_PROP_ID

    These properties indicate the hashing algorithm to be used when a hashing operation is performed.

CertSetCertificateContextProperty sets properties on a certificate; CertSetCRLContextProperty sets CRL properties; and CertSetCTLContextProperty sets CTL properties.

Three functions retrieve certificate properties. CertGetCertificateContextProperty retrieves certificate properties; CertGetCRLContextProperty retrieves CRL properties; and CertGetCTLContextProperty retrieves CTL properties.


Adding and Retrieving Certificate Store Properties

CertSetStoreProperty adds extended properties to a certificate store. CertGetStoreProperty retrieves any properties set on a certificate store. Currently, the only predefined certificate store property is a store's localized name.


Converting Encoded Types to Context Types

Three functions encode certificate information into certificate contexts contexts but do not add these context to any store. CertCreateCertificateContext encodes certificates; CertCreateCRLContext encodes CRLs; and CertCreateCTLContext encodes CTLs. Certificates created by one of these functions must be freed using the appropriate CertFree function.


Deleting Certificates

Three functions delete certificates from a store. CertDeleteCertificateFromStore deletes certificates; CertDeleteCRLFromStore deletes CRLs; and CertDeleteCTLFromStore deletes CTLs.


Duplicating Certificates

Three functions duplicate certificates. CertDuplicateCertificateContext duplicates a certificate context by incrementing its reference count and returning a pointer to the context. CertDuplicateCRLContext duplicates a CRL context, and CertDuplicateCTLContext duplicates a CTL context. Duplicates of CRL and CTL contexts are also made by increasing their reference counts. Certificates that are duplicate contexts created with any of the CertDuplicate functions must be freed using the appropriate CertFree function.


Listing (Enumeration) of Certificates

The Enumeration functions list the certificates in a store. To enumerate certificates, use CertEnumCertificatesInStore in a loop to process all the certificates in a store.

Because the name of the issuer of a CRL is usually known, a single function accommodates both finding a specific CRL by issuer name or enumerating the CRLs in a certificate store, CertGetCRLFromStore . Used in a loop, this function enumerates all of the CRLs in a store.


Finding Certificates

It is often necessary to search for certificates using flexible criteria. The CertFindCertificateInStore, CertFindCRLInStore, and CertFindCTLInStore functions provide this capability. The find functions can be used to filter certificates that meet specific criteria, such as all certificates that use a particular hash algorithm, from a store.


Memory Management Tasks

Three CertFree functions free the memory used by certificates. CertFreeCertificateContext frees the memory used by a certificate; CertFreeCRLContext frees the memory used by a CRL; and CertFreeCTLContext frees the memory used by a CTL. Each of these functions decreases the reference count on a certificate context. If the reference count is decreased to zero, the memory allocated for the certificate is released.


Store Management

Several functions provide services for the management of the state of a certificate store. CertOpenSystemStore opens a system store to access certificates saved in that store. CertOpenStore opens any store, including a system store, so that certificates can be accessed. CertDuplicateStore creates a copy of a store. CertSaveStore saves the contents of a store to a disk file or a memory location, and CertCloseStore closes stores, freeing the memory the store used.

CertControlStore manages a store while it is open. An application with an open store can be notified when the persisted state of that store has changed by some other process. This could happen if new certificates were copied to the local computer store from a domain control computer

When changes are discovered, the cached store can re-synchronize its cached store to match the persited state of the store. CertControlStore also supports a process that copies cached store changes to permanent storage when these changes in the cached store are not automatically saved.


Advanced Certificate Store Concepts

Microsoft® Windows NT® 5.0, adds new functionality to CryptoAPI for working with certificate stores. This includes the use of collection certificate stores, logical system certificate stores, and the ability to store links to contexts in stores rather than duplicates of the contexts.

For details on collection stores, see Logical and Collection Certificate Stores.

For details on logical system stores, see System Certificate Stores as Logical Stores.

For details on using links, see Using Certificate, CRL, and CTL Links.

For details about the registry locations of system logical stores and default physical stores associated with them, System Store Locations.


Logical and Collection Certificate Stores

As the number of certificates, CRLs, and CTLs that a user collects grows, the organization of those certificates becomes an issue. One possible solution is to create separate certificate stores to keep different kinds of certificates. This solution creates a new problem because an application may have to search several different stores to find a specific certificate. The use of logical or collection stores solves this problem.

A logical or collection certificate store is a group of physical stores that appear to an application as a single store. All member stores of a logical, collection store can be searched or enumerated with a single function call to either CertFindCertificateInStore or CertEnumCertificatesInStore.

The use of logical or collection stores also provides a flexibility that is difficult to achieve with paper records. A certificate in a single physical store may need to be a member of several different logical groups. Therefore, an individual physical store may be a member of more than one logical or collection store as shown in the following illustration.

This illustration presents the following basic, logical certificate store concepts:

  • A collection certificate store has a pointer to the first pointer block for that collection store.
  • Each pointer block of a collection store has a pointer to a sibling store and a pointer to the next pointer block of the collection.
  • Each sibling store in a collection is a simple physical certificate store
  • A simple certificate store may be a member sibling store in many different collection stores.
  • Certificates added to a collection store are physically added to one of the sibling stores in the collection.
  • Certificates in a sibling store may be accessed by any collection store in which the sibling store is a member.

Collection stores are built within an application by opening a collection store using CertOpenStore and then using CertAddStoreToCollection to add an open sibling store to the collection store. A sibling store can be deleted from a collection store by calling CertRemoveStoreFromCollection.


System Certificate Stores as Logical Stores

Default system stores, including MY, CA, and ROOT, are now implemented as logical stores with a number of pre-defined physical stores as their member stores. The member physical stores of a system store are opened automatically when the system store is opened. A user may add additional physical stores to any system store collection. The CryptoAPI function CertRegisterPhysicalStore adds a new physical store to a system store collection. CertUnregisterPhysicalStore disassociates a physical store from a logical system store. CertRegisterSystemStore creates a new system store under a registry hKey, while CertUnregisterSystemStore removes a system store from the registry.

In earlier CryptoAPI versions, a system store was a single, physical store and not a logical store that used a set of physical stores. In the CryptoAPI version initially supplied with Microsoft® Windows NT® 5.0, system stores have become logical stores with associated physical stores. All the certificates in an existing system store remain available, but the physical addition of new certificates will be made in the physical stores that make up the logical system store.

Users who prefer to continue to use physical system stores and not convert to logical stores can open system stores with the CERT_STORE_PROV_SYSTEM_REGISTRY provider. This provider will continue to use each system store as a single, physical store.

The functions CertEnumSystemStoreLocation, CertEnumSystemStore, and CertEnumPhysicalStore list system store locations, available system stores, and all physical stores that are members of a system store.

System stores are also relocatable. By default, a system store is opened relative to a registry subkey following a predefined pattern. See System Store Locations for details. Setting CERT_SYSTEM_STORE_RELOCATE_FLAG in the dwFlags parameter passed to CertOpenStore places a system store in the registry under a user specified registry subkey instead of the predefined one.


Using Certificate, CRL, and CTL Links

CertAddCertificateLinkToStore, CertAddCRLLinkToStore, and CertAddCTLLinkToStore add links to existing contexts into certificate stores rather than adding copies of those contexts. Adding links to stores makes the same physical certificate, CRL, or CTL available through several different stores. Changes made to the extended properties of a context from the store of the original context or from a store where a link to that context is stored are available in the store that holds the original context and in all other stores that have links to that context.

Assume that certificates A.1, A.2, A.3, and A.4 are originally in store A, and certificates B.1, B.2, B.3, and B.4 are originally in store B.

  • The diagram shows a link added in store B to certificate A.2 and a link added in store A to certificate B.2.
  • The original of certificate A.2 is still in store A. The original of B.2 is still in store B.
  • Any changes made in to the extended properties of certificate A.2 or certificate B.2 from either store A or store B will be available to both stores.
  • If a copy of certificate A.3 were made and stored in store B, any changes to the extended properties of the original A.3 certificate made from store A would not be visible in the new copy in store B. If changes were made to the extended properties of copy of certificate A.3 in store B, those changes would not affect the contents of the original, A.3 certificate and would not be visible from store A.


System Store Locations

A system store is a collection consisting of one or more physical sibling stores. For each system store, there are predefined physical sibling stores. After opening a system store such as MY at CERT_SYSTEM_STORE_CURRENT_USER, the store provider calls CertOpenStore to open each of the physical stores in the system store collection. In the open process, each of these physical stores is added to the system store collection using CertAddStoreToCollection. All of the certificates in those physical stores are available through the logical system store collection.

For each system store registry location, the predefined systems stores are:

MY
Root
Trust
CA

In registry location CERT_STORE_CURRENT_USER, there is also a predefined UserDS store. A smart card store is planned for this location.

CERT_SYSTEM_STORE_CURRENT_USER system stores are at registry location HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates.

The pre-defined physical stores associated with those system stores are:

System Store | Physical Store
MY | .Default
Root | .Default
 | .LocalMachine
Trust | .Default
 | .GroupPolicy
 | .LocalMachine
CA | .Default
 | .GroupPolicy
 | .LocalMachine
UserDS | .UserCertificate

CERT_SYSTEM_LOCAL_MACHINE system stores are at registry location HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates.

The pre-defined physical stores are associated with those system stores are

System Store | Physical Store
MY | .Default
Root | .Default
 | .GroupPolicy
Trust | .Default
 | .GroupPolicy
CA | .Default
 | .GroupPolicy

CERT_SYSTEM_STORE_CURRENT_SERVICE are at registry location HKEY_LOCAL_MACHINE\Software\Microsoft\Crytography\Services\<ServiceName>\SystemCertificates.

The pre-defined physical stores associated with those system stores are:

System Store | Physical Store
MY | .Default
Root | .Default
 | .LocalMachine
Trust | .Default
 | .LocalMachine
CA | .Default
 | .LocalMachine

CERT_SYSTEM_STORE_SERVICES system stores are at registry location HKEY_LOCAL_MACHINE\Software\Microsoft\Cryptography\Services\<ServiceName>\SystemCertificates.

The pre-defined physical stores associated with those system stores are:

System Store | Physical Store
ServiceName\MY | .Default
ServiceName\Root | .Default
 | .LocalMachine
ServiceName\Trust | .Default
 | .LocalMachine
ServiceName\CA | .Default
 | .LocalMachine

CERT_SYSTEM_STORE_USERS system stores are at registry location HKEY_USERS\<UserName>\Software\Microsoft\SystemCertificates.

The pre-defined physical stores associated with those system stores are:

System Store | Physical Store
userid\MY | .Default
 | .LocalMachine
userid\Root | .Default
 | .LocalMachine
userid\Trust | .Default
 | .LocalMachine
userid\CA | .Default
 | .LocalMachine

CERT_SYSTEM_CURRENT_USER_GROUP_POLICY system stores are at registry location HKEY_CURRENT_USER\Software\Policy\Microsoft\SystemCertificates.

CERT_SYSTEM_LOCAL_MACHINE_GROUP_POLICY system stores are at registry location HKEY_LOCAL_MACHINE\Software\Policy\Microsoft\SystemCertificates.

The pre-defined physical stores associated with those system stores are:

System Store | Physical Store
MY | .Default
Root | .Default
Trust | .Default
CA | .Default

Additional physical stores can be associated with a system store using CertRegisterPhysicalStore.

CERT_SYSTEM_STORE_SERVICE and CERT_SYSTEM_STORE_USERS stores are opened by prefixing the name of the store in the string passed to pvPara with the service or user name such as "ServiceName\Trust" or ".Default\MY." For Microsoft® Windows NT®, the CERT_SYSTEM_STORE_SERVICES or CERT_SYSTEM_STORE_USERS location can open the same store in CERT_SYSTEM_CURRENT_SERVICE or CERT_SYSTEM_CURRENT_USER by using the textual SID of the current service or user. For Windows® 95, the string returned by GetUserName is used.

Stores in CERT_SYSTEM_STORE_USER_GROUP_POLICY and CERT_SYSTEM_LOCAL_MACHINE_GROUP_POLICY in a network setting are downloaded to the client machine from the Group Policy Template (GPT) during machine startup or user logon. These stores may be updated on the client computer after startup or logon when the GPT is changed on the domain server by an administrator. The CertControlStore function allows an application to be notified when stores in either of these locations have changed.

The following system store locations can be opened remotely:

CERT_SYSTEM_STORE_LOCAL_MACHINE
CERT_SYSTEM_STORE_SERVICES
CERT_SYSTEM_STORE_USERS
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

System store locations are opened remotely by prefixing the store name in the string passed to pvPara with the computer name. Examples of remote system store names are:

ComputerName\CA
\\ComputerName\CA
ComputerName\ServiceName\Trust
\\ComputerName\ServiceName\Trust


Certificate Management Example Code

The following example code demonstrates how to use many of the certificate functions. This code uses some cryptographic function calls that are described in earlier sections and in the "CryptoAPI Reference."

For examples of code used to open certificate stores, see Example Code for Opening a Certificate Store.

For more general certificate store code examples, see Example Code for Fundamental Certificate Store Operations.

For examples of code for certificate verification, see Example Code for Certificate Verification Operations.

For example code for user defined functions including functions used in many of the examples, see Example Code for User Defined Functions.

For code to list system store locations, system stores or the physical stores that are members of a system store, see Example Code for Listing System and Physical Stores.


Example Code for Opening a Certificate Store

The following examples provide the code to open common certificate stores.

//********************************************************************
// 1. Open the system store, "MY"

HCERTSTORE hSysStore;
hSysStore = CertOpenStore(
   CERT_STORE_PROV_SYSTEM,   // The store provider type.
   0,                        // The encoding type is not needed.
   NULL,                     // Use the default HCRYPTPROV.
   CERT_SYSTEM_STORE_CURRENT_USER,
                             // Set store location in a registry
                             // location.
   L"MY"                     // The store name as a unicode string.
   );
// Substitute in other common system store names for "MY"
// including "root", "trust", or "CA".

//********************************************************************
// 2. Open a memory store.

HCERTSTORE hMemStore;
hMemStore = CertOpenStore(
   CERT_STORE_PROV_MEMORY,   // The memory provider type.
   0,                        // The encoding type is not needed.
   NULL,                     // Use the default HCRYPTPROV.
   0,                        // Accept the default dwFlags.
   NULL                      // pvPara not used.
   );

//********************************************************************
// 3. Open a store from disk.
// In this example, the read only flag is set.
HANDLE       hFile;
HCERTSTORE   hFileStore;
LPCSTR       pszFileName = "TestStor2.sto"
//  First, obtain a file handle.
if( !(hFile = CreateFile(
    pszFileName,                  // The file name
    GENERIC_READ|GENERIC_WRITE,   // Access mode:
                                  // read from and write to this file
    0,                            // Share Mode
    NULL,                         // Security
    OPEN_ALWAYS,                  // How to create
    FILE_ATTRIBUTE_NORMAL,        // File Attributes
    NULL)))                       // Template
{
    printf("Could not open %s On Disk\n", pszFileName);
    goto error_routine;
}
//   At this point, and data in the open file that precedes the
//   serialized cert store data may be used. The file pointer must
//   be placed at the beginning of the cert store data before
//   CertOpenStore with the CERT_STORE_PROV_FILE provider is called.
//   Open the store
if ( ! (hFileStore = CertOpenStore(
    CERT_STORE_PROV_FILE,     //  Load certificates from a file.
    0,                        //  Encoding type not used.
    NULL,                     //  Use the default HCRYPTPROV.
    CERT_STORE_READONLY_FLAG  //  See the LOWORD of dwFlags to make
                              //  the store read only.
    hFile                     //  The handle for the open file
                              //  that is the source of the
                              //  certificates.
    )))
{
    printf("Could not open the file store. \n");
    goto error_routine;
}
// Include code to work with the certificates
// The data file from which the certificate store information has been
// read is still open. Any data in that file that follows the
// serialized store can be read from the file and used at this point.

// Close the file store and the file.
CertCloseStore(
        file_store,
        CERT_CLOSE_STORE_CHECK_FLAG);
CloseHandle(hFile);
error_routine:
//  Here include any code to be done if the disk file
//  could not be opened

//********************************************************************
// 4. Open a file based store using CERT_STORE_PROV_FILENAME
//  The pvPara parameter here is the name of an existing file.
//  The function fails if the file does not exist.
//  The file is not opened using CreateFile before the call to
//  CertOpenStore.
//  CERT_STORE_PROV_FILENAME_A is used if the filename is in ASCII,
//  CERT_STORE_PROV_FILENAME would be used if the filename was a
//  unicode string.
#define ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
HCERTSTORE    hFileStoreHandle;
if ( ! (hFileStoreHandle = CertOpenStore(
       CERT_STORE_PROV_FILENAME,    // The store provider type.
       ENCODING_TYPE,               // If needed, use the usual
                                    // encoding types.
       NULL,                        // Use the default HCRYPTPROV.
       0,                           // Accept the default for all
                                    // dwFlags.
       L"FileStore.sto"             // The name of an existing file
                                    // as a unicode string.
        )))
   printf("Error opening file store. \n");
else
   printf("The file store is open. \n");

//********************************************************************
// 5. Open a collection store.
// Note that the collection store is empty.
// Certificates, CRLs, and CTLs can be added to and found in
// stores that are added as sibling stores to the collection store.
HCERTSTORE  hCollectionStoreHandle;
HCERTSTORE  hSiblingStoreHandle;
if( !(hCollectionStoreHandle = CertOpenStore(
     CERT_STORE_PROV_COLLECTION,
     0,        // For CERT_STORE_PROV_COLLECTION,
               // the rest of the parameters
               // should be 0 or NULL.
     NULL,
     0,
     NULL)))
   printf("Error opening Store from disk. \n");
else
   printf("Opened the COLLECTION Store \n");
// Open the sibling store as a file based store.
if ( !( hSiblingStoreHandle = CertOpenStore(
       CERT_STORE_PROV_FILENAME,    // The store provider type.
       ENCODING_TYPE,               // If needed, use the usual
                                    // encoding type.
       NULL,                        // Use the default HCRYPTPROV.
       0,                           // Accept the default for all
                                    // dwFlags.
       L"siblstore.sto"             // The name of an existing file
                                    // as a unicode string.
        )))
   printf("Error opening sibling file store. \n");
else
   printf("The sibling file store is open. \n");
// The open sibling store can now be added to the collection
// using CertAddStoreToCollection and processing of certificates can
// begin.
if(CertAddStoreToCollection(
          hCollectionStoreHandle,
          hSiblingStoreHandle,
          CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,
          1))
    printf("A sibling store has been added to the collection. \n");
// All processing of the certificates in the
// collection store will also involve the certificates in the sibling
// store.

//********************************************************************
// 6. Open a register store
HKEY hkResult;
HCERTSTORE  hRegStore = NULL;
// A register subkey must have been opened with RegOpenKeyEx or
// RegCreateKeyEx. A handle to the open register subkey, hkResult, is
// returned in one of parameters of RegOpenKeyEx or RegCreateKeyEx.
if( ! (hRegStore = CertOpenStore(
      CERT_STORE_PROV_REG,
      0,                    // No encoding type is needed.
      NULL,                 // Accept the default HCRYPTPROV.
      0,                    // Accept the default dwFlags.
      hkResult              // hkResult is the handle of a
                            // register subkey opened by RegOpenKeyEX
                            // or created/opened by RegCreateKeyEX.
      )))
   printf("The register store was not opened. \n");
else
   printf("The register store opened. \n");
// Begin processing certificates in the register based store.

//********************************************************************
// 7. Open a certificate store based on a PKCS7 message
HCERTSTORE        hSystemStore;
HCERTSTORE        hLastStore;
CRYPT_DATA_BLOB   message_blob;
// Initialize the message blob.
HCERTSTORE hSystemStore = CertOpenStore(
   CERT_STORE_PROV_SYSTEM,   // The store provider type.
   0,                        // The encoding type is not needed.
   NULL,                     // Use the default HCRYPTPROV.
   CERT_SYSTEM_STORE_CURRENT_USER,
                             // Set store location in a registry
                             // location.
   L"CA"                     // The store name as a unicode string.
   );
message_blob.cbData = 0;
message_blob.pbData = NULL;
// Get the cbData length
if(CertSaveStore(
        hSystemStore,
        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
        CERT_STORE_SAVE_AS_PKCS7,
        CERT_STORE_SAVE_TO_MEMORY,
        &message_blob,
        0))
    printf("The length  is %d \n",message_blob.cbData);
else
    printf("Save store failed.\n");
// Allocate the memory or pbData
if( ! (message_blob.pbData = (BYTE *)malloc(message_blob.cbData)))
     printf("memory allocation failed.\n");
else
     printf("memory allocated.\n");
//  Get the contents of pbData
if(CertSaveStore(
        hSystemStore,
        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
        CERT_STORE_SAVE_AS_PKCS7,
        CERT_STORE_SAVE_TO_MEMORY,
        &message_blob,
        0))
   printf("Saved the store to a memory blob\n");
else
   printf("Save store failed.\n");
if( ! (hLastStore = CertOpenStore(
   CERT_STORE_PROV_PKCS7,
   PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
   NULL,
   0,
   &message_blob)))
  printf("Did not open message store.\n");
else
  printf("The message store is open. \n");
// Clean up memory.

handle_error:
CertCloseStore(hLastStore, CERT_CLOSE_STORE_CHECK_FLAG);
CertCloseStore(hSystemStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG);


Example Code for Fundamental Certificate Store Operations.

This code demonstrates the following tasks:

  • Opening and closing stores in memory.
  • Opening and closing a system store.
  • Finding a certificates in a store that meets some criteria.
  • Adding the retrieved certificate to a store in memory.
  • Saving the store in memory to a file on disk.
#define _WIN32_WINNT 0x0400
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//********************************************************************
// Create a new certificate store in memory, retrieve a
// certificate from the system store and add it to the new
// store, and then save the new store to disk.

void main(void)
{
//********************************************************************
// Declare the variables.
HCERTSTORE      hSystemStoreHandle;        // The system store handle.
HCERTSTORE      hTempStoreHandle;          // A memory store handle.
PCCERT_CONTEXT  DesiredCert = NULL;
HANDLE          hStoreFileHandle = NULL;
LPCSTR          pszFileName = "TestStor.sto";

//*******************************************************************
// Open a new certificate store in memory.

if(hTempStoreHandle = CertOpenStore(
      CERT_STORE_PROV_MEMORY,    // A memory store
      0,                         // Not needed for a memory store.
      NULL,                      // Use the default provider.
      0,                         // No flags
      NULL))                     // Not needed
   printf("Opened a memory store. \n");
else
{
   printf( "Error opening a memory store. \n");
   goto handle_error;
}
// If successful, hTempStoreHandle is the cert store handle.

//********************************************************************
// Open the MY system store using CertOpenStore

if(hSystemStoreHandle = CertOpenStore(
     CERT_STORE_PROV_SYSTEM, // The system store will be a
                             // virtual store.
      0,                     // Encoding type not need with this PROV.
      NULL,                  // Accept the default HCRYPTPROV.
      CERT_SYSTEM_STORE_CURRENT_USER,
                             // Set the system store location in the
                             // registry.
      L"MY"))                // Could have used other predefined
                             // system stores
                             // including CA or Root
   printf("Opened the MY system store. \n");
else
{
   printf( "Could not open the MY system store. \n");
   goto handle_error;
}
// If the call was successful, hStoreHandle is now the handle of
// a system cert store.

//********************************************************************// Get a certificate that has the string "Microsoft" in its subject.

if(DesiredCert=CertFindCertificateInStore(
      hSystemStoreHandle,
      MY_ENCODING_TYPE,            // Use X509_ASN_ENCODING
      0,
      CERT_FIND_SUBJECT_STR,
      L"Microsoft",
      DesiredCert))
   printf("The desired certificate was found. \n");
else
{
   printf("Could not find the desired certificate. \n");
   goto handle_error;
}
// If the call was successful, DesiredCert is a pointer to a certificate.

//********************************************************************
// Add the system certificate to the new store in memory.

if(CertAddCertificateContextToStore(
      hTempStoreHandle,           // The store handle.
      DesiredCert,                // The pointer to a certificate.
      CERT_STORE_ADD_USE_EXISTING,
      NULL
      ))
   printf("Added a certificate to the memory store. \n");
else
{
   printf("Could not add the certificate to the memory store. \n");
   goto handle_error;
}

//********************************************************************
// Create a file to save the new store and certificate into.

if(hStoreFileHandle = CreateFile(
      pszFileName,        // File path
      GENERIC_WRITE,      // Access mode
      0,                  // Share Mode
      NULL,               // Security
      CREATE_ALWAYS,      // How to create
      FILE_ATTRIBUTE_NORMAL,
                          // File Attributes
      NULL))              // Template
   printf("Created a new file on disk. \n");
else
{
   printf("Could not create a file on disk. \n");
   goto handle_error;
}
// If the call was successful, hStoreFileHandle is the required file handle.

//********************************************************************
// Save the store and certificate to a file.

if( CertSaveStore(
      hTempStoreHandle,    // Store handle
      0,                   // Unused
      CERT_STORE_SAVE_AS_STORE,
      CERT_STORE_SAVE_TO_FILE,
      hStoreFileHandle,    // This is the handle of an open disk file.
      0))
   printf("Saved the memory store to disk. \n");
else
{
   printf("Could not save the memory store to disk. \n");
   goto handle_error;
}

//********************************************************************
// Do any other processing here.

//********************************************************************
// Clean up memory and end.
handle_error:
if(DesiredCert != NULL)
   CertFreeCertificateContext(DesiredCert);
if(hTempStoreHandle != NULL)
   CertCloseStore(
      hTempStoreHandle,
      CERT_CLOSE_STORE_CHECK_FLAG);
if(hSystemStoreHandle != NULL)
   CertCloseStore(
      hSystemStoreHandle,
      CERT_CLOSE_STORE_CHECK_FLAG);
if(hStoreFileHandle != NULL)
   CloseHandle(hStoreFileHandle);
printf("All of the stores and files are closed. \n");
return;
}


Example Code for Certificate Verification Operations

This code demonstrates the following:

  • Opening and closing the system store.
  • Finding a certificate by Subject name.
  • Using CertVerifyTimeValidity to check the certificate's validity.
#define _WIN32_WINNT 0x0400
#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//********************************************************************
//  This codes demonstrates
//   Opening and closing a system store
//   Finding a certificate by Subject name
//   Using the CertVerifyTimeValidity function to check the
//   certificate's validity

void main(void)
{
//********************************************************************
// Declare Variables.
HCERTSTORE      hSystemStoreHandle = NULL;
PCCERT_CONTEXT  pTargetCert=NULL;
char            szSubjectName[] = "Microsoft"; // A string to be found
                                               // in a certificate
                                               // subject.
long            nReturn;
PCERT_INFO          pTargetCertInfo;

//********************************************************************
// Call CertOpenStore to open the ROOT store.
if(hSystemStoreHandle = CertOpenStore(
      CERT_STORE_PROV_SYSTEM,
      0,
      NULL,
      CERT_SYSTEM_STORE_CURRENT_USER,
      L"ROOT"))
   printf("The Root store is open. \n");
else
{
   printf( "Error opening the Root store.\n");
   goto handle_error;
}
// If successful, hStoreHandle is the open system cert store handle.

//********************************************************************
// Get a particular certificate using CertFindCertificateInStore.
if(pTargetCert = CertFindCertificateInStore(
      hSystemStoreHandle,     // Store handle
      MY_ENCODING_TYPE,       // Encoding type
      0,                      // Not used
      CERT_FIND_SUBJECT_STR_A,// Find type. Find a string in the
                              // certificate's subject.
      szSubjectName,          // The string to be searched for.
      pTargetCert))           // Previous context
   printf("Found the certificate. \n");
else
{
   printf("Could not find the required certificate");
   goto handle_error;
}
// If successful, pTargetCert is a pointer to the desired
// certificate.

//********************************************************************
// Check the certificate validity.
pTargetCertInfo = pTargetCert->pCertInfo;
nReturn = CertVerifyTimeValidity(
      NULL,               // Use current time
      pTargetCertInfo);   // Pointer to CERT_INFO
if(nReturn<0)
   printf("Certificate not valid yet. \n");
else
   if(nReturn>0)
      printf("Certificate is expired. \n");
   else
      printf("Certificate is valid. \n");

//********************************************************************
// Clean up memory and quit.
handle_error:
if (pTargetCert)
   CertFreeCertificateContext(pTargetCert);
if(hSystemStoreHandle)
   CertCloseStore(hSystemStoreHandle,
        CERT_CLOSE_STORE_CHECK_FLAG);
printf("The certificate has been freed and the store closed.\n");
return;
}


Example Code for User Defined Functions

The first function code is for a subroutine that enumerates all the certificates in a store until a particular certificate is found with an issuer name that matches a string passed as a parameter. This code demonstrates:

  • The enumeration of certificates.
  • Getting the issuer name from each enumerated certificate.
  • Comparing the retrieved name with the desired name for each enumerated certificate.
  • Returning a pointer to the CERT_CONTEXT created when a match is made.
// GetSubjectCert() - A function to enumerate certificates
// in the store and get a handle to one of them based on issuer
// name.

#define _WIN32_WINNT 0x0400
#include <stdio.h>
#include <windows.h>
#include "wincrypt.h"
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
PCCERT_CONTEXT GetSubjectCert(
     HCERTSTORE hCertStore,       // the store to search
     LPCTSTR pszSearchName)       // the string to match
{

//********************************************************************
// Declare variables.
PCCERT_CONTEXT   pCertContext = NULL;
BOOL             fFound = FALSE;
BOOL             fMore = TRUE;
DWORD            dwSize = 0;
LPSTR            pszSubjectName;
LPSTR            pszNameFound;
CERT_NAME_BLOB   NameBlob;

//********************************************************************
//  Enumerate the certificates in the store until a match is found.
while(fMore && !fFound)
{
    if(!(pCertContext = CertEnumCertificatesInStore(
      hCertStore,
      pCertContext)))
    {
        // The end of the store has been reached. Get out of the loop.
        fMore=FALSE;
        break;
     }
     NameBlob = pCertContext->pCertInfo->Issuer;
     // Call CertNameToStr to get dwSize, the length of the
     // CertNameString
     dwSize = CertNameToStr(
         MY_ENCODING_TYPE,        // Encoding type
         &NameBlob,               // the subject from the pCertInfo
         CERT_SIMPLE_NAME_STR,    // Type of string
         NULL,                    // Place to return string.
                                  // In the first pass, NULL since
                                  // space for the name string has not
                                  // yet been allocated.
         0);                      // Size of the name string
     if (dwSize<2)        // If the string length returned is
                          // less than 2, the function could not
                          // determine a valid name string length.
                          // The function failed.
      {
          // The call to the function failed. Get out of the loop.
          printf("Error First pass of getting Name String1");
          fMore = FALSE;
          break;
      }
      // Allocate memory for the subject name string.
      if(!(pszSubjectName = (LPSTR)malloc(dwSize)))
      {
          // Memory allocation failed. Get out of the loop.
          printf("Error Allocating Memory");
          fMore = FALSE;
          break;
      }
      //  Make second call to CertNameToStr to get the string.
     dwSize = CertNameToStr(
          MY_ENCODING-TYPE,       // Encoding type
          &NameBlob,              // CERT_NAME_BLOB
          CERT_SIMPLE_NAME_STR,   // Type
          pszSubjectName,         // Place to return string
          dwSize);                // Size of string (chars)
     if(dwSize<2)
     {
           // If the length returned is less than 2,
           // the function failed. Get out of the loop.
           printf("Error in second pass.\n");
           fMore = FALSE;
           break;
      }
      pszNameFound = strstr(pszSubjectName,
                             pszSearchName);
      if(pszNameFound)
      {
          // The string searched for was matched. Get out of the loop.
          printf("Target Certificate %s Found \n", pszNameFound);
          fFound = TRUE;
          break;
}  // end while
free(pszSubjectName);
if(!fFound)
{
   printf("Target Cert Not Found\n");
   CertFreeCertificateContext(pCertContext);
   return NULL;
}
else
    return (pCertContext);   // return the whole context that included
                             // the subject name string.
}       // end of function

The following function is used to print an error message and exit a program. It is used the example code for several CryptoAPI functions.

void handle_error(char *s){
    printf("An error occured in running the program.\n");
    printf("%s\n\n",s);
    printf("Program terminating.\n");
    exit(1);
}


Example Code for Listing System and Physical StoresScenario

Example Code for Listing System and Physical Stores

This code enumerates the system certificate store locations, the system certificate stores, and the physical stores associated with each system store. The code demonstrates the creation of callback functions and callback functions that call other call back functions.

#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>

typedef struct _ENUM_ARG {
    BOOL        fAll;
    BOOL        fVerbose;
    DWORD       dwFlags;
    const void  *pvStoreLocationPara;
    HKEY        hKeyBase;
} ENUM_ARG, *PENUM_ARG;

// The following function is defined in a separate file.
void handle_error(char *s);

//*****************************************************************
// Declare functions. Definitions of these functions are at the
// end of this file.
static void DisplayPhysicalStoreInfo(
       PCERT_PHYSICAL_STORE_INFO pStoreInfo);
static BOOL GetSystemName(
       const void *pvSystemStore,
       DWORD dwFlags,
       PENUM_ARG pEnumArg,
       LPCWSTR *ppwszSystemName );
static BOOL WINAPI EnumPhyCallback(
       const void *pvSystemStore,
       DWORD dwFlags,
       LPCWSTR pwszStoreName,
       PCERT_PHYSICAL_STORE_INFO pStoreInfo,
       void *pvReserved,
       void *pvArg);
static BOOL WINAPI EnumSysCallback(
       const void *pvSystemStore,
       DWORD dwFlags,
       PCERT_SYSTEM_STORE_INFO pStoreInfo,
       void *pvReserved,
       void *pvArg);
static BOOL WINAPI EnumLocCallback(
       LPCWSTR pwszStoreLocation,
       DWORD dwFlags,
       void *pvReserved,
       void *pvArg);

//********************************************************************
// Begin main.
void main(void)
{

//********************************************************************
// Declare variables.
    BOOL fVerbose = FALSE;
    DWORD dwExpectedError = 0;
    DWORD dwLocationID = CERT_SYSTEM_STORE_CURRENT_USER_ID;
    DWORD dwFlags = 0;
    CERT_PHYSICAL_STORE_INFO PhyStoreInfo;
    ENUM_ARG EnumArg;
    LPSTR pszStoreParameters = NULL;
    LPSTR pszStoreLocationPara = NULL;
    LPWSTR pwszStoreParameters = NULL;
    LPWSTR pwszSystemName = NULL;
    LPWSTR pwszPhysicalName = NULL;
    LPWSTR pwszStoreLocationPara = NULL;
    void *pvSystemName;
    void *pvStoreLocationPara;
    DWORD dwNameCnt = 0;
    LPCSTR pszTestName;
    BOOL fRelocate = FALSE;
    HKEY hKeyRelocate = HKEY_CURRENT_USER;
    LPSTR pszRelocate = NULL;
    HKEY hKeyBase = NULL;
    char x;
//********************************************************************
//  Initalize variables.
    memset(&PhyStoreInfo, 0, sizeof(PhyStoreInfo));
    PhyStoreInfo.cbSize = sizeof(PhyStoreInfo);
    PhyStoreInfo.pszOpenStoreProvider = sz_CERT_STORE_PROV_SYSTEM_W;
    pszTestName = "Enum";
    pvSystemName = pwszSystemName;
    pvStoreLocationPara = pwszStoreLocationPara;
    memset(&EnumArg, 0, sizeof(EnumArg));
    EnumArg.dwFlags = dwFlags;
    EnumArg.hKeyBase = hKeyBase;

if (pwszStoreLocationPara) {
    printf("System Store Location Parameter :: %S\n",
       pwszStoreLocationPara);
    EnumArg.pvStoreLocationPara = pvStoreLocationPara;
    }
else if (fRelocate)
         EnumArg.pvStoreLocationPara = pvStoreLocationPara;
EnumArg.fAll = TRUE;
dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK;
dwFlags |= (dwLocationID << CERT_SYSTEM_STORE_LOCATION_SHIFT) &
    CERT_SYSTEM_STORE_LOCATION_MASK;

printf("Begin enumeration of Store Locations.\n");
if(!(CertEnumSystemStoreLocation(
    dwFlags,
    &EnumArg,
    EnumLocCallback
    )))
    handle_error("Enum of locations failed.");
printf("\n\nBegin enumeration of system Stores.\n");
printf("Hit enter to begin.");
scanf("%c",&x);
if(!(CertEnumSystemStore(
    dwFlags,
    pvStoreLocationPara,
    &EnumArg,
    EnumSysCallback
    )))
    handle_error("Enum system stores failed.");

printf("\n\nEnumerate the Physical stores for the My system store.\n");
if(!(CertEnumPhysicalStore(
    L"MY",
    dwFlags,
    &EnumArg,
    EnumPhyCallback
    )))
    handle_error("Enumeration of physical stores failed.");
printf("Physical stores enumerated.\n");
}    //   end of main.

// begin function definitions.
static void DisplayPhysicalStoreInfo(
    PCERT_PHYSICAL_STORE_INFO pStoreInfo
    )
{
    DWORD dwFlags;
    LPCSTR pszStoreProvider = pStoreInfo->pszOpenStoreProvider;
    if (0xFFFF >= (DWORD) pszStoreProvider)
        printf("      OpenStoreProvider: %d", pszStoreProvider);
    else
        printf("      OpenStoreProvider: %s", pszStoreProvider);

    if (0xFFFF >= (DWORD) pszStoreProvider) {
        if (CERT_STORE_PROV_FILENAME_A == pszStoreProvider)
            printf(" (FILENAME_A)");
        else if (CERT_STORE_PROV_FILENAME_W == pszStoreProvider)
            printf(" (FILENAME_W)");
        else if (CERT_STORE_PROV_SYSTEM_A == pszStoreProvider)
            printf(" (SYSTEM_A)");
        else if (CERT_STORE_PROV_SYSTEM_W == pszStoreProvider)
            printf(" (SYSTEM_W)");
        else if (CERT_STORE_PROV_SYSTEM_REGISTRY_A == pszStoreProvider)
            printf(" (SYSTEM_REGISTRY_A)");
        else if (CERT_STORE_PROV_SYSTEM_REGISTRY_W == pszStoreProvider)
            printf(" (SYSTEM_REGISTRY_W)");
        else if (CERT_STORE_PROV_PHYSICAL_W == pszStoreProvider)
            printf(" (PHYSICAL_W)");
    }
    printf("\n");
    printf("      OpenEncodingType: 0x%x\n",
           pStoreInfo->dwOpenEncodingType);
    dwFlags = pStoreInfo->dwFlags;
    printf("      Flags: 0x%x", dwFlags);
    if (dwFlags)
        printf(" ::");
    if (dwFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
        printf(" ADD_ENABLE");
    if (dwFlags & CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG)
        printf(" OPEN_DISABLE");
    if (dwFlags & CERT_PHYSICAL_STORE_REMOTE_OPEN_DISABLE_FLAG)
        printf(" REMOTE_OPEN_DISABLE_FLAG");
    if (dwFlags & CERT_PHYSICAL_STORE_INSERT_COMPUTER_NAME_ENABLE_FLAG)
        printf(" INSERT_COMPUTER_NAME_ENABLE_FLAG");
    printf("\n");
    printf("      Priority: %d\n", pStoreInfo->dwPriority);
}

//********************************************************************
// Function definitions

static BOOL GetSystemName(
const void *pvSystemStore,
    DWORD dwFlags,
PENUM_ARG pEnumArg,
LPCWSTR *ppwszSystemName ){
*ppwszSystemName = NULL;
 if (pEnumArg->hKeyBase && 0 == (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG))
{
        printf("failed => RELOCATE_FLAG not set in callback\n");
        return FALSE;
}
else
     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG) {
        PCERT_SYSTEM_STORE_RELOCATE_PARA pRelocatePara;
        if (NULL == pEnumArg->hKeyBase) {
            handle_error("failed => RELOCATE_FLAG is set in callback");
        }
        pRelocatePara = (PCERT_SYSTEM_STORE_RELOCATE_PARA) pvSystemStore;
        if (pRelocatePara->hKeyBase != pEnumArg->hKeyBase) {
            handle_error("failed => wrong hKeyBase passed to callback");
        }
        *ppwszSystemName = pRelocatePara->pwszSystemStore;
    }
    else
    *ppwszSystemName = (LPCWSTR) pvSystemStore;
return TRUE;
}

//********************************************************************
// Callbacks.

static BOOL WINAPI EnumPhyCallback(
const void *pvSystemStore,
DWORD dwFlags,
LPCWSTR pwszStoreName,
PCERT_PHYSICAL_STORE_INFO pStoreInfo,
void *pvReserved,
void *pvArg ){
PENUM_ARG pEnumArg = (PENUM_ARG) pvArg;
LPCWSTR pwszSystemStore;
if (!GetSystemName(pvSystemStore, dwFlags, pEnumArg, &pwszSystemStore))
        handle_error("GetSystemName failed.");
printf("    %S", pwszStoreName);
if (pEnumArg->fVerbose &&
      (dwFlags & CERT_PHYSICAL_STORE_PREDEFINED_ENUM_FLAG))
      printf(" (implicitly created)");
printf("\n");
if (pEnumArg->fVerbose){
   printf("verbose is on.\n");
   DisplayPhysicalStoreInfo(pStoreInfo);
}
return TRUE;
}

static BOOL WINAPI EnumSysCallback(
const void *pvSystemStore,
DWORD dwFlags,
PCERT_SYSTEM_STORE_INFO pStoreInfo,
void *pvReserved,
void *pvArg
)
{
PENUM_ARG pEnumArg = (PENUM_ARG) pvArg;
LPCWSTR pwszSystemStore;
static int i=0;
char x;
if(i++ > 6){
   printf("Enum System store : Hit any key to continue.");
   scanf("%c",&x);
   i=0;
}
if (!GetSystemName(pvSystemStore, dwFlags, pEnumArg, &pwszSystemStore))
     handle_error("GetSystemName failed");

printf("  %S\n", pwszSystemStore);
if (pEnumArg->fAll || pEnumArg->fVerbose) {
    dwFlags &= CERT_SYSTEM_STORE_MASK;
    dwFlags |= pEnumArg->dwFlags & ~CERT_SYSTEM_STORE_MASK;
if (!CertEnumPhysicalStore(
      pvSystemStore,
      dwFlags,
      pEnumArg,
      EnumPhyCallback
      )) {
      DWORD dwErr = GetLastError();
      if (!(ERROR_FILE_NOT_FOUND == dwErr ||
            ERROR_NOT_SUPPORTED == dwErr))
               printf("    CertEnumPhysicalStore");
        }
    }
    return TRUE;
}

static BOOL WINAPI EnumLocCallback(
LPCWSTR pwszStoreLocation,
DWORD dwFlags,
void *pvReserved,
void *pvArg
)
{
PENUM_ARG pEnumArg = (PENUM_ARG) pvArg;
DWORD dwLocationID = (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) >>
   CERT_SYSTEM_STORE_LOCATION_SHIFT;
static int i=0;
char x;
if(i++ > 6){
   printf("Enum store locations : Hit any key to continue.");
   scanf("%c",&x);
   i=0;
}
printf("======   %S   ======\n", pwszStoreLocation);
if (pEnumArg->fAll) {
    dwFlags &= CERT_SYSTEM_STORE_MASK;
dwFlags |= pEnumArg->dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK;
if (!CertEnumSystemStore(
    dwFlags,
    (void *) pEnumArg->pvStoreLocationPara,
    pEnumArg,
    EnumSysCallback
    )) {
    DWORD dwErr = GetLastError();
    if (E_INVALIDARG == dwErr && pEnumArg->pvStoreLocationPara)
    // \\ComputerName, ServiceName, or \\ComputerName\Service
    // not supported for all store locations
              ;
    else if (!(ERROR_FILE_NOT_FOUND == dwErr ||
              ERROR_PROC_NOT_FOUND == dwErr))
        printf("  CertEnumSystemStore");
        }
    }
    return TRUE;
}


Certificate Management Functions

The following Win32® functions manage the storage, work with certificates, and manage certificate stores.

Function | Description
CertAddCertificateContextToStore | Adds a certificate context to the certificate store.
CertAddCRLContextToStore | Adds a CRL context to the certificate store.
CertAddCTLContextToStore | Adds a CTL context to the certificate store.
CertAddCertificateLinkToStore | Adds a link in a certificate store to a certificate context in a different store.
CertAddCRLLinkToStore | Adds a link in a store to a CRL context in a different store.
CertAddCTLLinkToStore | Adds a link in a store to a CTL context in a different Store.
CertAddEncodedCertificateToStore | Converts the encoded certificate to a certificate context and then adds the context to the certificate store.
CertAddEncodedCRLToStore | Converts the encoded CRL to a CRL context and then adds the context to the certificate store.
CertAddEncodedCTLToStore | Converts the encoded CTL to a CTL context and then adds the context to the certificate store.
CertAddSerializedElementToStore | Adds the serialized certificate or CRL element to the store.
CertAddStoreToCollection | Adds a sibling certificate store to a collection store.
CertCloseStore | Closes a certificate store handle.
CertControlStore | Notifies application when a change has been made to the persisted store, re-syncs the cached store with the persisted store and commits changes made in the cached store.
CertCreateCertificateContext | Creates a certificate context from an encoded certificate. The created context is not put in a certificate store.
CertCreateContext | Creates the specified context from the encoded bytes. The new context is not put into a store.
CertCreateCRLContext | Creates a CRL context from an encoded CRL. The created context is not put in a certificate store.
CertCreateCTLContext | Creates a CTL context from an encoded certificate trust list. The created context is not put in a certificate store.
CertDeleteCertificateFromStore | Deletes a certificate from the certificate store.
CertDeleteCRLFromStore | Deletes a CRL from the certificate store.
CertDeleteCTLFromStore | Deletes a CTL from the certificate store.
CertDuplicateCertificateContext | Duplicates a certificate context by incrementing its reference count.
CertDuplicateCRLContext | Duplicates a CRL context by incrementing its reference count.
CertDuplicateCTLContext | Duplicates a CTL context by incrementing its reference count.
CertDuplicateStore | Duplicates a store context by incrementing reference counts.
CertEnumCertificateContextProperties | Enumerates the properties for the specified certificate context.
CertEnumCRLContextProperties | Enumerates the properties for the specified CRL context.
CertEnumCTLContextProperties | Enumerates the properties for the specified CTL context.
CertEnumCertificatesInStore | Enumerates the certificate contexts in the certificate store.
CertEnumCRLsInStore | Enumerates the CRL contexts in a store.
CertEnumCTLsInStore | Enumerates the CTL contexts in the certificate store.
CertEnumPhysicalStore | Enumerates the physical stores for a specified system store.
CertEnumSubjectInSortedCTL | Enumerates through the TrustedSubjects in a sorted CTL context.
CertEnumSystemStore | Enumerates all available system stores.
CertEnumSystemStoreLocation | Enumerates all of the locations that have an available system store.
CertFindCertificateInStore | Finds the first, or next, certificate context in the certificate store meeting a search criteria.
CertFindCRLInStore | Finds the first, or next, CRL context in the certificate store meeting a search criteria.
CertFindCTLInStore | Finds the first, or next, CTL context in the certificate store meeting a search criteria.
CertFindSubjectInSortedCTL | Attempts to find the specified subject in a sorted CTL.
CertFreeCertificateContext | Frees a certificate context.
CertFreeCRLContext | Frees a CRL context.
CertFreeCTLContext | Frees a CTL context.
CertGetCertificateContextProperty | Gets a property of the specified certificate context.
CertGetCRLContextProperty | Gets a property of the specified CRL context.
CertGetCRLFromStore | Gets the first, or next, CRL context from the certificate store for the specified issuer certificate.
CertGetIssuerCertificateFromStore | Gets a certificate context from the certificate store for the fist, or next, issuer of the specified subject certificate.
CertGetStoreProperty | Gets a certificate store property
CertGetSubjectCertificateFromStore | Gets the subject certificate context, uniquely identified by its issuer and serial number, from the certificate store.
CertOpenStore | Opens a certificate store using the specified store provider.
CertOpenSystemStore | Opens a system certificate store based on a system name.
CertRegisterPhysicalStore | Adds a physical store to a system store collection.
CertRegisterSystemStore | Registers a system store.
CertRemoveStoreFromCollection | Removes a sibling certificate store from a collection store.
CertSaveStore | Saves the certificate store.
CertSerializeCertificateStoreElement | Serializes the certificate context's encoded certificate and its properties.
CertSerializeCRLStoreElement | Serializes the CRL context's encoded CRL and its properties.
CertSerializeCTLStoreElement | Serializes the CTL context's encoded CTL and its properties.
CertSetCertificateContextProperty | Sets a property for the specified certificate context.
CertSetCRLContextProperty | Sets a property for the specified CRL context.
CertSetCTLContextProperty | Sets a property for the specified CTL context.
CertSetStoreProperty | Sets a store property.
CertUnregisterPhysicalStore | Removes a physical store from a system store collection.
CertUnregisterSystemStore | Unregisters a system store.
CertVerifySubjectCertificateContext | Performs the enabled verification checks on the subject certificate using the issuer.


Helper Functions

There are a number of helper functions that are provided to make the task of managing certificates easier. They are listed in the following table, and details about them can be found in Certificate Helper Functions.

Function | Description
CertAlgIdToOID | Converts the CSP algorithm identifier to the ASN.1 Object Identifier string.
CertCompareCertificate | Compares two certificates to determine whether they are identical.
CertCompareCertificateName | Compares two certificate names to determine whether they are identical.
CertCompareIntegerBlob | Compares two integer blobs.
CertComparePublicKeyInfo | Compares two public keys to determine whether they are identical.
CertFindAttribute | Finds the first attribute identified by its Object Identifier.
CertFindExtension | Finds the first extension identified by its Object Identifier.
CertFindRDNAttr | Finds the first RDN attribute identified by its Object Identifier in the name list of the Relative Distinguished Names.
CertGetIntendedKeyUsage | Gets the intended key usage bytes from the certificate.
CertIsRDNAttrsInCertificateName | Compares the attributes in the certificate name with the specified RDN's array of attributes to determine whether all attributes are included there.
CertNameToStr | Converts a certificate name blob to a zero terminated string.
CertOIDToAlgId | Converts the ASN.1 Object Identifier string to the CSP algorithm identifier.
CertRDNValueToStr | Converts a Name Value to a null-terminated string.
CertVerifyCRLRevocation | Verifies that the subject certificate is not on the CRL.
CertVerifyCRLTimeValidity | Verifies the time validity of a CRL.
CertVerifyRevocation | Verifies the subject certificate is not on the CRL.
CertVerifyTimeValidity | Verifies the time validity of a certificate.
CertVerifyValidityNesting | Verifies that the subject's time validity nests within the issuer's time validity.
CryptExportPublicKeyInfo | Exports the public key information associated with the provider's corresponding private key.
CryptExportPublicKeyInfoEx | Exports the public key information associated with the provider's corresponding private key. This function differs from CryptExportPublicKeyInfo in that the user can specify the public key algorithm, overriding the default provided by the CSP.
CryptHashCertificate | Hashes the encoded content.
CryptHashPublicKeyInfo | Computes the hash of the encoded public key info.
CryptHashToBeSigned | Computes the hash of the "to be signed" information in the encoded signed content (CERT_SIGNED_CONTENT_INFO).
CryptImportPublicKeyInfo | Converts and imports the public key info into the provider and return a handle to the public key.
CryptImportPublicKeyInfoEx | Converts and imports the public key information into the provider and returns a handle to the public key. Additional parameters (over those specified by CryptImportPublicKeyInfo) that can be used to override defaults are provided to supplement the CERT_PUBLIC_KEY_INFO.
CryptSignAndEncodeCertificate | Encodes the "to be signed" information, signs this encoded information, and. encodes the resulting signed encoded information.
CryptSignCertificate | Signs the "to be signed" information in the encoded signed content.
CryptVerifyCertificateSignature | Verifies the signature of a subject certificate or a CRL using the public key info.


Creating Certificate Requests

To receive a certificate from a certification authority (CA), a user makes an electronic request to the CA via a certificate request, a specially formatted electronic message. This section discusses the process of creating a certificate request.

The following two illustrations show the initialization map for initializing all the data necessary to create a certificate request. The first illustration depicts the process for initializing a CERT_NAME_INFO structure for the Subject name in the certificate. That structure is then used as input to the CryptEncodeObject function, the output of which is the initialized (encoded) CERT_NAME_BLOB structure, which is pointed to by the Subject member of the CERT_REQUEST_INFO structure (shown in the second illustration).

Additionally, the CryptExportPublicKeyInfo function exports the public key into the CERT_PUBLIC_KEY_INFO structure, which is pointed to by the SubjectPublicKeyInfo member of the CERT_REQUEST_INFO structure.

If you want to add customized information to the request, this can be done by initializing a CRYPT_ATTR_BLOB structure with the data, including it in the CRYPT_ATTR_BLOB array, then pointing the rgValue member of a CRYPT_ATTRIBUTE structure contained in a CRYPT_ATTRIBUTE array, to the CRYPT_ATTR_BLOB array. Finally, the rgAttribute member of the CERT_REQUEST_INFO structure must be pointed to the CRYPT_ATTRIBUTE array.

Once the CERT_REQUEST_INFO structure is completely initialized, the CryptSignAndEncodeCertificate function can be used to prepare the data for transmission.

The following is a procedure for creating and initializing a certificate request. It is followed by example code demonstrating how to implement the procedure.

To create a certificate request and prepare it for transmission
  1. Create a string containing the certificate request Subject name.
  2. Declare a CERT_RDN_ATTR array, initializing each array element with the following data: the object ID string, the ValueType, the length of the string created in step 1, and the string created in step 1 (cast as a BYTE*).
  3. Declare a CERT_RDN array, initializing each element with the RDNAttr count, and the address of an index of the CERT_RDN_ATTR array initialized in step 2.
  4. Declare a CERT_NAME_INFO structure, initializing it with the number of CERT_RDN array elements, and the CERT_RDN array address.
  5. Call the CryptEncodeObject function, providing the CERT_NAME_INFO for the appropriate argument. Its output will be a CERT_NAME_BLOB structure that has been initialized with the encoded data.
  6. Set the Subject member of the CERT_REQUEST_INFO structure to point to the CERT_NAME_BLOB structure created and initialized in step 5.
  7. If extra custom information is to be included in the certificate request, a CRYPT_ATTR_BLOB array must be initialized with the custom data, and a CRYPT_ATTRIBUTE array, containing a CRYPT_ATTRIBUTE structure, must be initialized with the CRYPT_ATTR_BLOB array. For the sake of clarity, this step will not be demonstrated in the example code.
  8. The version number must be added to the CERT_REQUEST_INFO structure.
  9. Call the CryptExportPublicKeyInfo function to return an initialized CERT_PUBLIC_KEY_INFO structure.
  10. Set the SubjectPublicKeyInfo member of the CERT_REQUEST_INFO structure to point to the CERT_PUBLIC_KEY_INFO structure created in step 9.
  11. Call the CryptSignAndEncodeCertificate function, providing the CERT_REQUEST_INFO structure for the appropriate argument. This encodes the CERT_REQUEST_INFO structure and all of the data pointed to by it, signs this encoded information, and encodes the signed, encoded information.


Certificate Request Example Code

The following example code demonstrates the procedure outlined in the previous section. This example code creates a simple certificate request with one signer, a single RDN attribute, and no general attributes.

// This example code demonstrates how to create and encode a
// certificate request.

#include <stdio.h>
#include <windows.h>
#include "wincrypt.h"
#define CERT_SUBJECT_NAME "Elizabeth Jackson"
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
void BytesToStr(DWORD cb, void* pv, LPSTR sz);
void main(void)
{
// Declare and initialize

// A CERT_RDN_ATTR array.
// In this code, only one array element is used.

  CERT_RDN_ATTR rgNameAttr[] = {"2.5.4.3",  // pszObjId
  CERT_RDN_PRINTABLE_STRING,                // dwValueType
    strlen(CERT_SUBJECT_NAME),              // value.cbData
    (BYTE*)CERT_SUBJECT_NAME};              // value.pbData

// A CERT_RDN array.
// In this code, only one array element is used.

CERT_RDN rgRDN[] = {
    1,                 // rgRDN[0].cRDNAttr
    &rgNameAttr[0]};   // rgRDN[0].rgRDNAttr

// A CERT_NAME_INFO structure.

CERT_NAME_INFO Name = {
       1,                  // Name.cRDN
       rgRDN};             // Name.rgRDN

// Other variables and structures.

CERT_REQUEST_INFO    CertReqInfo;
CERT_NAME_BLOB       SubjNameBlob;
DWORD cbNameEncoded = 0;
BYTE* pbNameEncoded;
HCRYPTPROV hCryptProv = NULL; // Handle returned here
DWORD    cbPublicKeyInfo;
CERT_PUBLIC_KEY_INFO* pbPublicKeyInfo;
DWORD    cbEncodedCertReqSize;
CRYPT_OBJID_BLOB Parameters;
CRYPT_ALGORITHM_IDENTIFIER SigAlg;
BYTE* pbSignedEncodedCertReq;
char*    pSignedEncodedCertReqBlob;
BOOL fReturn = FALSE;

CryptEncodeObject(
    MY_ENCODING_TYPE,     // Encoding type
    X509_NAME,            // Struct type
    &Name,                // Address of CERT_NAME_INFO struct.
    NULL,                 // pbEncoded
    &cbNameEncoded);      // pbEncoded size

if(cbNameEncoded<1)
{
    printf("First call to CryptEncodeObject Failed\n");
    goto handle_error;
}

if(!(pbNameEncoded = (BYTE*)malloc(cbNameEncoded)))
{
    printf("pbNamencoded Malloc Failed\n");
    goto handle_error;
}

if(!CryptEncodeObject(
        MY_ENCODING_TYPE,    // Encoding type
        X509_NAME,           // Struct type
        &Name,               // Address of CERT_NAME_INFO struct.
        pbNameEncoded,       // pbEncoded
        &cbNameEncoded))     // pbEncoded size
{
    printf("Second call to CryptEncodeObject Failed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Set the Subject member of CertReqInfo to point to
// a CERT_NAME_INFO structure that
// has been initialized with the data from step 5.

SubjNameBlob.cbData = cbNameEncoded;
SubjNameBlob.pbData = pbNameEncoded;
CertReqInfo.Subject = SubjNameBlob;

// Generate custom information.  This step is not
// implemented in this code.

CertReqInfo.cAttribute = 0;
CertReqInfo.rgAttribute = NULL;
CertReqInfo.dwVersion = CERT_REQUEST_V1;

// Call CryptExportPublicKeyInfo to return an initialized
// CERT_PUBLIC_KEY_INFO structure.
// #1  Get a cryptographic provider.

if(!(CryptAcquireContext(
    &hCryptProv,        // Address for handle to be returned.
    NULL,               // Use the current user's logon name.
    NULL,               // Use the default provider.
    PROV_RSA_FULL,      // Need to do both encrypt & sign.
    NULL)))             // No flags needed.
{
    printf("Call to CryptAcquireContextFailed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Call CryptExportPublicKeyInfo to get the size of the returned
// information.

if(!(CryptExportPublicKeyInfo(
          hCryptProv,            // Provider handle
          AT_SIGNATURE,          // Key spec
          MY_ENCODING_TYPE,      // Encoding type
          NULL,                  // pbPublicKeyInfo
          &cbPublicKeyInfo)))     // Size of PublicKeyInfo
{
    printf("First call to CryptExportPublicKeyInfo failed\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Allocate the necessary memory.
if(!(pbPublicKeyInfo =
   (CERT_PUBLIC_KEY_INFO*)malloc(cbPublicKeyInfo)))
{
    printf("pbPublicKeyInfo Malloc Failed.\n");
    free(pbNameEncoded);
    goto handle_error;
}

// Call CryptExportPublicKeyInfo to get pbPublicKeyInfo.
if(!(CryptExportPublicKeyInfo(
          hCryptProv,            // Provider handle
          AT_SIGNATURE,          // Key spec
          MY_ENCODING_TYPE,      // Encoding type
          pbPublicKeyInfo,       // pbPublicKeyInfo
          &cbPublicKeyInfo)))    // Size of PublicKeyInfo
{
    printf("Second call to CryptExportPublicKeyInfo failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}
// Set the SubjectPublicKeyInfo member of the
// CERT_REQUEST_INFO structure to point to the CERT_PUBLIC_KEY_INFO
// structure created.

CertReqInfo.SubjectPublicKeyInfo = *pbPublicKeyInfo;

// Call CryptSignAndEncodeCertificate to encode, sign,
// and re-encode the CERT_REQUEST_INFO structure and the data
// pointed to by it.
//---------------------------------------------------------------

memset(&Parameters, 0, sizeof(Parameters));
SigAlg.pszObjId = szOID_OIWSEC_sha1RSASign;
SigAlg.Parameters = Parameters;

// Call CryptSignAndEncodeCertificate to get the size of the
// returned blob.
if(!(CryptSignAndEncodeCertificate(
          hCryptProv,                      // Crypto provider
          AT_SIGNATURE,                    // Key spec.
          MY_ENCODING_TYPE,                // Encoding type
          X509_CERT_REQUEST_TO_BE_SIGNED,  // Struct type
          &CertReqInfo,                    // Struct info
          &SigAlg,                         // Signature algorithm
          NULL,                            // Not used
          NULL,                            // pbSignedEncodedCertReq
          &cbEncodedCertReqSize)))         // Size of cert req
{
    printf("First call to CryptSignAndEncodeCertificate\n ");
    printf("failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}

// Malloc the necessary memory.
pbSignedEncodedCertReq = (BYTE*)malloc(cbEncodedCertReqSize);
if(!pbSignedEncodedCertReq)
{
    printf("pbSignedEncodedCertReq Malloc Failed\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    goto handle_error;
}
// Call CryptSignAndEncodeCertificate to get the
// returned blob.
if(!(CryptSignAndEncodeCertificate(
          hCryptProv,                     // Crypto provider
          AT_SIGNATURE,                   // Key spec.
          MY_ENCODING_TYPE,               // Encoding type
          X509_CERT_REQUEST_TO_BE_SIGNED, // Struct type
          &CertReqInfo,                   // Struct info
          &SigAlg,                        // Signature algorithm
          NULL,                           // Not used
          pbSignedEncodedCertReq,         // Pointer
          &cbEncodedCertReqSize)))        // Sizeif(!fReturn)
{
    printf("Second call to CryptSignAndEncodeCertificate\n ");
    printf("failed.\n");
    free(pbNameEncoded);
    free(pbPublicKeyInfo);
    free(pbSignedEncodedCertReq);
    goto handle_error;
}
// View the signed and encoded certificate request blob.

pSignedEncodedCertReqBlob =
                        new char[(cbEncodedCertReqSize *2) +1];
// Call routine to convert the byte blob to ASCII HEX. See the
// subroutine that follows this code segment.
BytesToStr(cbEncodedCertReqSize,
            pbSignedEncodedCertReq,
            pSignedEncodedCertReqBlob);
// Show the unicode string.
printf("%S\n",pSignedEncodedCertReqBlob);

//---------------------------------------------------------------
// Free memory.
//---------------------------------------------------------------
free(pbNameEncoded);
free(pbPublicKeyInfo);
free(pbSignedEncodedCertReq);
handle_error:
printf("have reached the end.\n");
}

//************************************************************
// BytesToStr() - Converts the bytes into CHAR hex. Needs
// (cb * 2 + 1) * sizeof(CHAR) bytes of space in sz.
//************************************************************
void BytesToStr(DWORD cb, void* pv, LPSTR sz)
{

    BYTE* pb = (BYTE*) pv;
int b;
DWORD i;
    for (i = 0; i<cb; i++)
    {
     b = (*pb & 0xF0) >> 4;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        b = *pb & 0x0F;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';

        pb++;
    }
    *sz++ = 0;
}


Using Certificates with Messages

Although it is possible to use certificates with the base cryptographic functions, it is much easier to use certificates with the low-level message functions or the simplified message functions. Therefore, it is recommended that you use these functions when sending or receiving messages that incorporate certificates.

For examples of using certificates with the low-level message functions see Signed Message Example Code, Enveloped Message Example 1, Enveloped Message Example 2, and Hashed Message Example Code.

For examples of using certificates with the simplified message functions see Example Code Using CryptSignMessage, Example Code Using CryptVerifyMessageSignature, Example Code Using CryptEncryptMessage, and Example Code Using CryptDecryptMessage.

For information on all of the low-level message functions, see Low Level Message Functions.

For information on all of the simplified message functions, see Simplified Message Functions.


Certificate Encoding/Decoding

Microsoft® CryptoAPI version 2.0 supports the encoding and decoding of certificates. CryptoAPI includes an extensive, flexible system of functions and C structures that allows you to encode and decode in various ways. If, however, you want to achieve interoperability with other systems, you should use the X.509 certificate structure and ASN.1 encoding. The CryptoAPI supports both of these standards.

For an overview of data encoding and decoding, see Encoding and Decoding Data.


The Certificate Context

A certificate context is simply a C structure that contains an encoding type member, a handle to a certificate store, a pointer to the original encoded certificate blob, and a pointer to a CERT_INFO C structure. It is the CERT_INFO structure that contains most of the certificate information.

The first step that must be taken when decoding a certificate blob is to call CertCreateCertificateContext, passing it a pointer to the encoded certificate (blob). When this function is called, it creates a duplicate of the encoded certificate, creates a structure of type CERT_CONTEXT, and creates a structure of type CERT_INFO. As shown in the following illustration, a certificate context includes the original certificate blob, a C structure of type CERT_CONTEXT, and a C structure of type CERT_INFO. One of the members of the CERT_CONTEXT structure points to the CERT_INFO structure and another to the encoded certificate blob.


Decoding the CERT_INFO Structure

The CERT_INFO structure is the heart of the certificate. It contains, either in direct form or in encoded form, all the basic information in the certificate. The following illustration shows the CERT_INFO structure, with all the encoded members shown as shaded.

It should be noted that the IssuerUniqueID and SubjectUniqueID structure members are a part of the X.509 version 2 certificate implementation, and are seldom used anymore. Their functionality has been replaced by the version 3 "Extensions" functionality.

If the information contained in the encoded (shaded) members Issuer and Subject is needed, those members must be decoded. To decode one of these members, the CryptDecodeObject function must be used. The process of decoding one of these members is depicted in the following illustration.

In the illustrated case, the CryptDecodeObject function outputs a CERT_NAME_INFO structure, an array of CERT_RDN structures, a corresponding array of CERT_RDN_ATTR structures, and a string containing the name. It is important to note that what is contained in the string is determined by the other members of the CERT_RDN_ATTR structure. For example, if the pszObjId member is set to "2.5.4.3", this equates to a common name. If it were set to "2.5.4.10" then the string would contain an organization name. For a list of these ObjIds, see CERT_RDN_ATTR.

The dwValueType member contains information pertaining to the type of string—for example, if it were set to CERT_RDN_PRINTABLE_STRING the value member would contain a byte-width, zero-terminated character string; if it were set to CERT_RDN_UNICODE_STRING, it would contain a double-width (word-sized) character string.

The encoded object (data member) is always provided as the input to the CryptDecodeObject function, and the output is a C structure that may or may not have encoded members, depending on how far into the process you are.

There is one other member that requires some decoding, and that is the Extension member. Although it is not encoded at the CERT_INFO level, it does contain some encoded information. To decode this information, proceed as shown in the following illustration.

In the CERT_INFO structure, data member rgExtension is a pointer to an array of CERT_EXTENSION structures. Each CERT_EXTENSION structure has a Value data member that is in encoded form and needs to be decoded. The Value data member is passed to the CryptDecodeObject function, and then the output from the function depends on the value of the pszObjId data member. Notice that in the illustration, two different structures are produced, one of type CERT_BASIC_CONSTRAINTS_INFO and one of type CERT_AUTHORITY_KEY_ID_INFO, depending on the value of pszObjId.


Encoding the CERT_INFO Structure

The encoding process is essentially just the reverse process to that described in the preceding section. If, for example, you want to add an encoded Issuer to a CERT_INFO structure, you would use the following procedure. Also refer to the illustration that follows the procedure.

To add an encoded Issuer to a CERT_INFO structure
  1. Create a string containing the name you wish to use.
  2. Create an array of CERT_RDN_ATTR structures, one of which you would initialize to contain the proper information about the string you just created.
  3. Create an array of CERT_RDN structures, one of which has the information about the array of CERT_RDN_ATTR structures you just initialized.
  4. Create a CERT_NAME_INFO structure that has a pointer to the array of CERT_RDN structures that you just created.
  5. Call CryptEncodeObject to get the size of the output encoded blob, passing it the address of the CERT_NAME_INFO structure that you just created.
  6. Allocate memory for the output encoded blob.
  7. Call CryptEncodeObject again, passing it the same information, but now passing it the address of the memory just allocated.
  8. Set the Issuer.cbData member of the CERT_INFO structure to the size returned in step 5, and the Issuer.pbData member to the address obtained in step 6. The encoded Issuer blob now resides there.

Suppose you wanted to initialize and encode some certificate extension information. You would use the following procedure. Also see the illustration that follows the procedure.

To add encoded extension information to a CERT_INFO structure
  1. Create and initialize an extension information structure—for this example it is a CERT_BASIC_CONSTRAINTS_INFO structure.
  2. Call CryptEncodeObject, passing it the address of the structure just created, to get the size of the output encoded blob.
  3. Allocate memory for the output encoded blob.
  4. Call CryptEncodeObject again, passing the same information, except now pass in the address of the allocated memory.
  5. Create an array of CERT_EXTENSION structures.
  6. Initialize one of the CERT_EXTENSION structures so that the pszObjId is the proper string for the data contained in Value, and that Value contains the encrypted data blob that was output from the call to CryptEncodeObject.
  7. Initialize the rgExtension member of the CERT_INFO structure to point to the array of CERT_EXTENSION structures.


Using Certificate Trust Lists

As explained in Authentication Using Certificates, a trust must exist between the recipient of a signed message and the signer of the message. One method of establishing this trust is through the use of a certificate, an electronic document verifying that entities or persons are who they claim to be. A certificate is issued to an entity by a third party that is trusted by both of the other parties. So, each recipient of a signed message must decide if the issuer of the signer's certificate is trustworthy. The CryptoAPI has implemented a methodology to allow application developers to create applications that automatically verify certificates against a predefined list of trusted certificates or roots. This list of trusted entities (called subjects) is called a Certificate Trust List (CTL).

The following example of CTL use involves an intranet (intra-company network) network administrator who wants to control just which outside sources are trusted. In this case the administrator can create a list of trusted certificates or roots, sign it, and make the list available to all clients on the network in the form of a CTL. An application designed to use this CryptoAPI functionality would then only accept signed messages or downloaded software that was signed by entities on the list.


CTL Overview

The CryptoAPI CTL is a list of items that has been signed by a trusted entity. The list of items could be anything, such as a list of hashes of certificates, or a list of file names. The important thing is that all the items in the list are authenticated (approved) by the signing entity.

The primary use of this functionality is to verify signed messages, using the CTL as a source of trusted root certificates. In this case, the CTL is a list of hashed certificate contexts.

In addition to certificates and certificate revocation lists (CRL), the CryptoAPI certificate store now supports CTLs. This means that a CTL_CONTEXT structure has been added that is very similar to the certificate and CRL context structures, and that these CTL contexts may be persisted to the certificate store.

The CTL_CONTEXT is very similar to the certificate and CRL context structures. However, the main difference is that, unlike the certificate and CRL context structures, the CTL_CONTEXT structure contains a HCRYPTMSG member. This handle is opened by a call to any of the functions that return a CTL_CONTEXT structure, making it possible to use the message functions to verify the CTL's signature. This verification is necessary to ensure that the CTL being used is not a bogus CTL planted by some rogue entity.

Several functions are provided for managing CTLs. These include:

CertAddCTLContextToStore
CertAddEncodedCTLToStore
CertCreateCTLContext
CertDeleteCTLFromStore
CertDuplicateCTLContext
CertEnumCTLContextProperties
CertEnumCTLsInStore
CertFindCTLInStore
CertFindSubjectInCTL
CertFreeCTLContext
CertGetCTLContextProperty
CertSerializeCTLStoreElement
CertSetCTLContextProperty
CertVerifyCTLUsage
CryptMsgEncodeAndSignCTL
CryptMsgGetAndVerifySigner
CryptMsgSignCTL


Creating, Signing, and Storing a CTL

The following procedures describe how to create a signed CTL and save it to a certificate store.

To create and sign a CTL
  1. Create an array of items to be stored in the CTL. In the case of trusted certificates, this must be the SHA1 or MD5 hashes of the trusted certificates.
  2. Initialize a CTL_INFO structure that includes the array of items just created.
  3. Initialize a CMSG_SIGNED_ENCODE_INFO structure.
  4. Call CryptMsgEncodeAndSignCTL. This function call returns a pointer to a signed, encoded CTL (in a PKCS #7 format) that contains the list of items created in step 1.
To add a CTL to a certificate store
  1. Get a pointer to a signed and encoded CTL.
  2. Open the target certificate store with a call to CertOpenStore.
  3. Call CertAddEncodedCTLToStore.


Verifying a CTL

To make it more difficult for an interloper to substitute a bogus CTL for an existing one, the signature on the CTL should be verified each time the CTL is used. If the CTL does not contain a trusted signature, then it should not be used.

To verify a CTL signature
  1. Open the certificate store containing the desired CTL.
  2. Get a handle to a CTL_CONTEXT for the CTL. This can be done by calling any of the functions that return a handle to the CTL_CONTEXT, such as CertFindCTLInStore.
  3. Call CryptMsgGetAndVerifySigner, passing the CTL_CONTEXT retrieved in step 2 in the hCryptMsg argument, a handle to the certificate store containing the certificate of the trusted source for CTLs in the rghSignerStore argument, and the CMSG_TRUSTED_SIGNER_FLAG in the dwFlags argument. If the function call returns TRUE, then the signature was verified, and a pointer to the CTL signer's PCERT_CONTEXT is returned in the ppSigner parameter.


Verifying Signed Messages By Using CTLs

One of the advantages of using CTLs is that applications can be designed that can automatically verify signed messages against trusted certificates without bothering the user with dialog boxes. It also gives some control to a network administrator as to what sources should be trusted. The following procedure could be used to verify the signature of a signed message by using a CTL.

To verify a signed message by using a CTL
  1. Decode the message.
    1. Get a pointer to the received message (the encoded blob).
    2. Call CryptMsgOpenToDecode, passing the necessary arguments.
    3. Call CryptMsgUpdate once, passing in the handle retrieved in step 2, and a pointer to the data that is to be decoded. This causes the appropriate actions to be taken on the message, depending on the message type.
  2. Verify the signature of the decoded, signed message, and get a pointer to the signer's CERT_CONTEXT.

    This can be done by calling CryptMsgGetAndVerifySigner, passing the message handle retrieved in step 1.c in the hCryptMsg argument. If the function call returns TRUE, then the signature was verified, and a pointer to the signer's PCERT_CONTEXT is returned in the ppSigner parameter.

  3. Confirm that the signer is a trusted source.
    1. Open the certificate store containing the appropriate CTL.
    2. Get a pointer to the CTL_CONTEXT by calling CertFindCTLInStore.
    3. To confirm that the signer is a trusted source, call CertFindSubjectInCTL, passing the pointer retrieved in the previous step in the pCtlContext argument, CTL_CERT_SUBJECT_TYPE in the dwSubjectType argument, and the pointer to the CERT_CONTEXT retrieved in step 2.a in the pvSubject argument. If the function call returns TRUE, the CERT_CONTEXT passed to the function is a trusted source in the CTL.


Using Low-Level Message Functions

For the purpose of this discussion, a message is any data that has been encoded (and usually signed or encrypted) for transmission to another person or entity, or such data that has been received from another person or entity. This data may sometimes be signed data, and often includes certificates.

The low-level message functions provide the necessary functionality to encode data for transmission, and decode data that has been received. Functionality is also provided to decrypt and verify the signatures of received messages.


PKCS 7--An overview.

PKCS 7—An Overview

The low-level message functions adhere to RSA PKCS #7 Cryptographic Message Syntax Standard, published by RSA Laboratories, a division of RSA Data Security, Inc. The specification is available on their web site, http://www.rsa.com. To most effectively use the low-level message functions, you should become familiar with this specification. A few of its definitions are highlighted here.

The PKCS #7 standard describes a general syntax for data that may have cryptography applied to it, such as digital signatures and digital envelopes. The syntax admits recursion, so that, for example, one envelope can be nested inside another, or one party can sign digital data that has already been put into an envelope. It also allows arbitrary attributes, such as signing time, to be authenticated along with the content of a message. Further, it provides for other attributes, such as countersignatures, to be associated with a signature.

The type of data contained in a PKCS #7 message is called its content type. There are two classes of content types—Base and Enhanced.

  • Base. Content types in this class contain only data with no cryptographic enhancements. Presently there is only one content type in this class, the Data content type.
  • Enhanced. Content types in this class contain data of some type (possibly encrypted), and other cryptographic enhancements (such as hashes or signatures).

The content in the Enhanced class employs encapsulation, giving rise to the terms, outer content (the one containing the enhancements) and inner content (the one being enhanced). For example, an Enhanced class might contain the Data content type (Base class) that has a signature included with it. In this case, the Data content type is the inner content and the combination of the Data content type and the signature forms the outer content.

The content types defined in PKCS #7 standard are:

  • Data. An octet (BYTE) string.
  • Signed Data. Consists of content of any type and encrypted message digests of the content for zero or more signers.
  • Enveloped Data. Consists of encrypted content of any type and encrypted content-encryption keys for one or more recipients. The combination of encrypted content and encrypted content-encryption key for a recipient is a digital envelope for that recipient.
  • Signed-and-Enveloped Data. Consists of encrypted content of any type, encrypted content-encryption keys for one or more recipients, and doubly encrypted message digests for one or more signers. The double encryption consists of an encryption with a signer's private key followed by an encryption with the content-encryption key.
  • Digested Data. Consists of content of any type and a message digest of the content.

    Note Throughout the PKCS #7 specification, the terms digest and digested are used to refer to the value produced from applying a hashing algorithm to data. Throughout this manual we have used the terms "hash" and "hashed" for the same purpose. For example, the data type used with the low-level message functions is called hashed rather than digested. For the purposes of this document the two sets of terms may be used interchangeably.

  • Encrypted Data. Consists of encrypted content of any type. Unlike the enveloped-data content type, the encrypted-data content type has neither recipients nor encrypted content-encryption keys. Keys are assumed to be managed by other means.


Low-Level Message Functions Overview

The low-level message functions include the following:

  • CryptMsgCalculateEncodedLength. Calculates a length that is large enough (sometimes a little larger than necessary) to contain the returned value of the encoded message given the message type, encoding parameters, and total length of the data to be updated.
  • CryptMsgClose. Closes a cryptographic message handle.
  • CryptMsgControl. Performs a special control function after the final CryptMsgUpdate (see the description later in this list) of an encoded/decoded cryptographic message.
  • CryptMsgCountersign. Countersigns an unencoded signature that already exists in a message.
  • CryptMsgCountersignEncoded. Countersigns an already existing signature (encoded SignerInfo, as defined by PKCS #7).
  • CryptMsgGetParam. Gets a parameter (such as the content) after encoding/decoding a cryptographic message. Called after the final CryptMsgUpdate (see the description later in this list).
  • CryptMsgOpenToDecode. Opens a cryptographic message for decoding.
  • CryptMsgOpenToEncode. Opens a cryptographic message for encoding.
  • CryptMsgUpdate. Updates the content of a cryptographic message. Depending on how the message was opened, the content is either encoded or decoded.
  • CryptMsgVerifyCountersignatureEncoded. Verifies a countersignature in terms of the SignerInfo data structure (as defined by PKCS # 7).

One of the advantages of using these functions is that when a message is opened by using one of the open functions, it maintains state until it is closed. This allows a message to be constructed piecemeal by using the CryptMsgUpdate function. The disadvantage of using these functions, as opposed to the simplified message functions (described in Using Simplified Message Functions) is that more function calls are required—that is, you must do more of the work yourself. If the simplified message functions are used, more of the work is done for you.

Some of the additional work that you must do when using these functions involves making calls to functions in other categories, such as certificates or cryptographic functions. For example, to initialize some of the required data structures when using the low-level message functions, you must first call some of the certificate functions. The simplified message functions do some of this work for you.

The general procedures you use to encode or decode a message are as follows (The details will be covered in later sections):

To encode a message
  1. Initialize the appropriate data structures for the desired data type.
  2. Call CryptMsgOpenToEncode, passing the necessary arguments.

    When calling CryptMsgOpenToEncode, and the data that is to be provided to CryptMsgUpdate has already been message-encoded, then the appropriate object identifier should be passed in pszInnerContentObjID (for example, "1.2.840.113549.1.7.2" for szOID_RSA_signedData). If pszInnerContentObjID is NULL, then the inner content type is assumed not to have been previously encoded, and is processed appropriately.

  3. Call CryptMsgUpdate as many times as necessary to complete the message. On the last call, the fFinal parameter should be set TRUE (for the details, see CryptMsgUpdate).
  4. Call CryptMsgGetParam to get a pointer to the desired parameters, such as the content.
  5. Close the message by calling CryptMsgClose.

This procedure results in an encoded message of a type specified in the function calls.

To decode a message
  1. Call CryptMsgOpenToDecode, passing the necessary arguments.

    To maintain compatibility with Internet Explorer version 3.0, the dwMsgType parameter is provided. Signed data created in Internet Explorer version 3.0 does not contain header information. Therefore, if such a message is extracted from file signatures, the message type must be passed into the function. If zero is passed into the dwMsgType parameter, the function will read the message type from the header on the message. If the header is missing, the function call will fail. If successful, a handle to the opened message is returned.

  2. Call CryptMsgUpdate once. This causes the appropriate actions to be taken on the message, depending on the message type.
  3. If you want additional processing of the message, such as additional decryption or signature verification, call CryptMsgControl, passing the desired action in dwCtrlType.
  4. Call CryptMsgGetParam to get a pointer to the desired parameters, such as the content.
  5. Call CryptMsgClose to close the message.


Encoding and Decoding with Low-Level Message Functions

The low-level message functions can be used to encode or decode the data types described in the following sections (the signed and enveloped, and encrypted data types are not currently implemented).


Signed Data

This data type consists of content of any type and encrypted message hashes (digests) of the content for zero or more signers. The resultant hash(es) can be used to confirm that the original message has not been modified since signing and that a particular person or entity signed the data.


Encoding Signed Data

The general tasks required to encode a signed message are depicted in the following illustration and are described in the list that follows it. There can be multiple signers, hashing algorithms, and certificates. Also, while the illustration shows only certificates, certificate revocation lists (CRL) can be used as well. They would fit into the illustration wherever certificates are shown.

The sequence of events for encoding signed data, as depicted in the previous illustration, is as follows:

  1. The data is created (if necessary) and a pointer to it is retrieved.
  2. A certificate store is opened that contains the signer's certificate.
  3. The private key from the certificate is retrieved. There are two properties that must be set on the certificate before using it. One is used to tie a certificate to a particular CSP and, within that CSP, to a particular private key. The other is used to indicate which hashing algorithm is to be used when a digest operation is called for. These need only be set once.
  4. From the certificate property, the hash algorithm is determined.
  5. A hash (digest) of the data is created by sending the data through the hashing function.
  6. The signature is created by using the private key, obtained through the property on the certificate, to encrypt the hash.
  7. The following data is included in the finished, signed message:
    • The original data to be signed
    • The hash algorithms
    • The signatures
    • The signer info structures, which includes the signerID (certificate issuer and serial number)
    • The signer's certificates (optional)

The tasks just illustrated and listed describe the simplest case. A more complex case is when authenticated attributes are included in the message. When the content type is anything but the Data type (a BYTE string), or there is at least one authenticated attribute along with any data type, there are two standard authenticated attributes required: the content (data) type, and the hash of the content. Under these circumstances, the CryptoAPI automatically provides these two required attributes. The low-level message functions hash the authenticated attributes, encrypt the hash with the private key, and provide this as the signature.

Use the low-level message functions to accomplish the tasks just listed, by using the following procedure.

To encode a signed message using the CryptoAPI
  1. Create or retrieve the content.
  2. Get a cryptographic provider.
  3. Get the signer certificates.
  4. Initialize the CMSG_SIGNER_ENCODE_INFO structure.
  5. Initialize the CMSG_SIGNED_ENCODE_INFO structure.
  6. Call CryptMsgCalculateEncodedLength to get the size of the encoded message blob. Allocate memory for it.
  7. Call CryptMsgOpenToEncode, passing in CMSG_SIGNED for dwMsgType, and a pointer to CMSG_SIGNED_ENCODE_INFO for pvMsgEncodeInfo. As a result of this call, you get a handle to the opened message.
  8. Call CryptMsgUpdate, passing in the handle retrieved in step 7, and a pointer to the data that is to be signed and encoded. This function can be called as many times as necessary to complete the encoding process.
  9. Call CryptMsgGetParam, passing in the handle retrieved in step 7 and the appropriate parameter types to access the desired, encoded data. For example, pass in CMSG_CONTENT_PARAM to get a pointer to the entire PKCS #7 message.

    If the result of this encoding is to be used as the inner data for another encoded message, such as an enveloped message, the CMSG_BARE_CONTENT_PARAM parameter must be passed. For example code showing this, see Enveloped Message Example 2.

  10. Close the message by calling CryptMsgClose.

The result of this procedure is an encoded message that contains the original data, the encrypted hash of that data (signature), and the signer information. Also, you now have a pointer pointing to the desired, encoded blob.


Decoding Signed Data

The following procedure will allow you to decode a signed data type.

To decode a signed message
  1. Get a pointer to the encoded blob.
  2. Call CryptMsgOpenToDecode, passing the necessary arguments.
  3. Call CryptMsgUpdate once, passing in the handle retrieved in step 2, and a pointer to the data that is to be decoded. This causes the appropriate actions to be taken on the message, depending on the message type.
  4. Call CryptMsgGetParam, passing in the handle retrieved in step 2, and the appropriate parameter types to access the decoded data. For example, pass in CMSG_CONTENT_PARAM to get a pointer to the decoded content.

The following procedure allows you to verify the signature of a decoded, signed message.

To verify the signature of a decoded, signed message
  1. Call CryptMsgGetParam, passing in the message handle and CMSG_SIGNER_CERT_INFO_PARAM to get the signer's CERT_INFO from the message.
  2. Call CertOpenStore, to open a temporary store that is initialized with the certificates from the message.
  3. Call CertGetSubjectCertificateFromStore to get the signer's CERT_INFO from the certificates included in the message.
  4. Call CryptMsgControl, passing in CMSG_CTRL_VERIFY_SIGNATURE to verify the signatures.
  5. Call CryptMsgClose to close the message.

The result of these procedures is that the signature was verified and a pointer was retrieved to the decoded message content obtained in step 4 of the procedure for decoding a signed message.


Signed Message Example Code

The following example code demonstrates the process of encoding, decoding, and verifying the signature of a signed message.

//=============================================================
// EXAMPLE CODE FOR CREATING A SIGNED MESSAGE.
//=============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// the content will usually exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                   "Signed Message";       // The message
char* pszContent = szContent;              // A string pointer
BYTE* pbContent = (BYTE*) pszContent;      // A byte pointer
DWORD cbContent = sizeof(szContent);       // Size of message

AfxMessageBox(pszContent);                 // Display original message

//-------------------------------------------------------------
// Get a handle to a cryptographic provider.
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
                &hCryptProv,      // Address for handle to be returned
                NULL,             // Use the current user's logon name
                NULL,             // Use the default provider
                PROV_RSA_FULL,    // Specifies the provider type
                0);               // Zero allows access to private keys
if(!fReturn)
{
    AfxMessageBox("CryptAcquireContext failed");
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to your signature certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pSignerCert = NULL;
// For the implementation of GetMySignerCert(), see the function
// at the end of this example code.
pSignerCert = GetMySignerCert(hStoreHandle);
if(!pSignerCert)
{
    AfxMessageBox( "Error Getting Signer Cert");
    return;
}

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure.
//-------------------------------------------------------------
DWORD                         HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);    // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;    // Then set the
                                           //   necessary field.

//-------------------------------------------------------------
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO    SignerEncodeInfo;

memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;

// Create an array of one. NOTE: Currently, there can be only one
// signer.
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
SignerEncodeInfoArray[0] = SignerEncodeInfo;

//-------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.
//-------------------------------------------------------------
CERT_BLOB    SignerCertBlob;

SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;

// Create an array of one. Only one certificate is included.
CERT_BLOB    SignerCertBlobArray[1];
SignerCertBlobArray[0] = SignerCertBlob;

CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;

memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded = 1;
SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbEncodedBlob;
BYTE        *pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                        MY_ENCODING_TYPE,       // Msg encoding type
                        0,                      // Flags
                        CMSG_SIGNED,            // Msg type
                        &SignedMsgEncodeInfo,   // Ptr. to struct.
                        NULL,                   // Inner content ObjID
                        cbContent);             // size of content
if(0 == cbEncodedBlob)
{
    AfxMessageBox("Getting cbEncodedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    AfxMessageBox("Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
                MY_ENCODING_TYPE,        // Encoding type
                0,                       // Flags
                CMSG_SIGNED,             // Msg type
                &SignedMsgEncodeInfo,    // Pointer to structure
                NULL,                    // Inner content ObjID
                NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("OpenToEncode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
                    hMsg,         // Handle to the message
                    pbContent,    // Pointer to the content
                    cbContent,    // Size of the content
                    TRUE);        // Last call
if(!fResult)
{
    AfxMessageBox("MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
               hMsg,                      // Handle to the message
               CMSG_CONTENT_PARAM,        // Parameter type
               0,                         // Index
               pbEncodedBlob,             // Pointer to the blob
               &cbEncodedBlob);           // Size of the blob
if(!fResult)
{
    AfxMessageBox("MsgGetParam failed");
    free(pbEncodedBlob);
    CryptMsgClose(hMsg);
    return;
}else
    AfxMessageBox("Message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.

CertFreeCertificateContext(pSignerCert);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);

//=============================================================
// EXAMPLE CODE FOR DECODING A SIGNED MESSGE
//=============================================================

//-------------------------------------------------------------
// Open a message for decoding.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToDecode(
               MY_ENCODING_TYPE,      // Encoding type
               0,                     // Flags
               0,                     // Message type (get from msg.)
               hCryptProv,            // Cryptographic provider
               NULL,                  // Recipient info
               NULL);                 // Stream info
if(NULL == hMsg)
{
    AfxMessageBox("OpenToDecode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the encoded blob, using the data
// that was encoded in the previous section of code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                 hMsg,                 // Handle to the message
                 pbEncodedBlob,        // Pointer to the encoded blob
                 cbEncodedBlob,        // Size of the encoded blob
                 TRUE);                // Last call
if(!fResult)
{
    AfxMessageBox("Decode MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the message type.
//-------------------------------------------------------------
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType = 0;

fResult = CryptMsgGetParam(
                  hMsg,                   // Handle to the message
                  CMSG_TYPE_PARAM,        // Parameter type
                  0,                      // Index
                  &dwMsgType,             // Address for returned info
                  &cbData);               // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_TYPE_PARAM failed");
    free(pbEncodedBlob);
    return;
}

// Some applications may need to use a "switch" statement here
// and process the message differently depending on the
// message type.
if(dwMsgType != CMSG_SIGNED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of the content.
//-------------------------------------------------------------
DWORD    cbDecoded = 0;

fResult = CryptMsgGetParam(
                  hMsg,                   // Handle to the message
                  CMSG_CONTENT_PARAM,     // Parameter type
                  0,                      // Index
                  NULL,                   // Address for returned info
                  &cbDecoded);            // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Allocate Memory.
//-------------------------------------------------------------
BYTE    *pbDecoded = NULL;

pbDecoded = (BYTE *) malloc(cbDecoded);
if(NULL == pbDecoded)
{
    AfxMessageBox("Decode memory allocation failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get a pointer to the content.
//-------------------------------------------------------------
LPSTR    pDecodedString;

fResult = CryptMsgGetParam(
                  hMsg,                   // Handle to the message
                  CMSG_CONTENT_PARAM,     // Parameter type
                  0,                      // Index
                  pbDecoded,              // Address for returned info
                  &cbDecoded);            // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM #2 failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}else
    AfxMessageBox("Message decoded successfully");

pDecodedString = (LPSTR) pbDecoded;

AfxMessageBox(pDecodedString);

//=============================================================
// Verify the signature.
//=============================================================

//-------------------------------------------------------------
// Get the signer CERT_INFO from the message.
//-------------------------------------------------------------

// Get the size of memory required.
DWORD    cbSignerCertInfo = 0;

fResult = CryptMsgGetParam(
            hMsg,                         // Handle to the message
            CMSG_SIGNER_CERT_INFO_PARAM,  // Parameter type
            0,                            // Index
            NULL,                         // Address for returned info
            &cbSignerCertInfo);           // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Verify SIGNER_CERT_INFO #1 failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}

// Allocate memory.
PCERT_INFO    pSignerCertInfo = NULL;

pSignerCertInfo = (PCERT_INFO) malloc(cbSignerCertInfo);
if(NULL == pSignerCertInfo)
{
    AfxMessageBox("Verify memory allocation failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}

// Get the message certificate information (CERT_INFO
// structure).
fResult = CryptMsgGetParam(
            hMsg,                         // Handle to the message
            CMSG_SIGNER_CERT_INFO_PARAM,  // Parameter type
            0,                            // Index
            pSignerCertInfo,              // Address for returned info
            &cbSignerCertInfo);           // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Verify SIGNER_CERT_INFO #2 failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pSignerCertInfo);
    return;
}

//-------------------------------------------------------------
// Open a certificate store in memory using CERT_STORE_PROV_MSG,
// which initializes it with the certificates from the message.
//-------------------------------------------------------------
HCERTSTORE    hTempStore;

hTempStore = CertOpenStore(
               CERT_STORE_PROV_MSG,         // Store Provider type
               MY_ENCODING_TYPE,            // Encoding type
               hCryptProv,                  // Cryptographic provider
               0,                           // Flags
               hMsg);                       // Handle to the message
if(NULL == hTempStore)
{
    AfxMessageBox("Verify OpenStore failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pSignerCertInfo);
    return;
}

//-------------------------------------------------------------
// Find the signer's certificate in the store.
//-------------------------------------------------------------
PCCERT_CONTEXT    pSignerCertContext = NULL;

pSignerCertContext = CertGetSubjectCertificateFromStore(
                         hTempStore,            // Handle to store
                         MY_ENCODING_TYPE,      // Encoding type
                         pSignerCertInfo);      // Pointer to
                                                //   retrieved
                                                //   CERT_CONTEXT
if(NULL == pSignerCertContext)
{
    AfxMessageBox("Verify GetSubjectCert failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pSignerCertInfo);
    CertCloseStore(hTempStore, CERT_CLOSE_STORE_FORCE_FLAG);
    return;
}

//-------------------------------------------------------------
// Use the CERT_INFO from the signer's certificate to verify
// the signature.
//-------------------------------------------------------------
PCERT_INFO pSignerCertificateInfo = pSignerCertContext->pCertInfo;

fResult = CryptMsgControl(
               hMsg,                          // Handle to the message
               0,                             // Flags
               CMSG_CTRL_VERIFY_SIGNATURE,    // Control type
               pSignerCertificateInfo);       // Pointer to the
                                              //   retrieved CERT_INFO
if(!fResult)
{
    AfxMessageBox("Verify Signature failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pSignerCertInfo);
    CertCloseStore(hTempStore, CERT_CLOSE_STORE_FORCE_FLAG);
    return;
}
else
    AfxMessageBox("Verify Signature Succeeded");

//-------------------------------------------------------------
// Clean up.
//-------------------------------------------------------------
free(pbEncodedBlob);
free(pbDecoded);
free(pSignerCertInfo);
CertCloseStore(hTempStore, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);

}

//************************************************************
// GetMySignerCert() - A function to list all the certs in the
// store and get a handle to one of them.
//************************************************************
PCCERT_CONTEXT GetMySignerCert(HCERTSTORE hCertStore)
{
    PCCERT_CONTEXT    pPrevCertContext = NULL;
    PCCERT_CONTEXT    pCertContext = NULL;
    BOOL              fReturnFlag = FALSE;
    BOOL              fTestFlag;
    DWORD             dwSize = NULL;
    KEY_PROV_INFO*    pKeyInfo = NULL;

    while(TRUE)
    {
        pCertContext = CertEnumCertificatesInStore(
                       hCertStore,
                       pPrevCertContext);
        if(!pCertContext)
        {
            fTestFlag = FALSE;
            break;
        }
        else
        {
            // For clarity, this code searches for the first
            // occurrence of a certificate containing an exchange key.
            // This works here, as there is only one pair of
            // certificates in the store. Normally you would search
            // for a name as well as the key type.

            // Call CertGetCertificateContextProperty to get the
            // structure size.

            fReturnFlag = CertGetCertificateContextProperty(
                           pCertContext,
                           CERT_KEY_PROV_INFO_PROP_ID,
                           NULL,
                           &dwSize);
            if(FALSE == fReturnFlag)
                AfxMessageBox("Error Getting Key Property");

            // Allocate memory for the returned structure.
            if(pKeyInfo)
                free(pKeyInfo);
            pKeyInfo = (KEY_PROV_INFO*)malloc(dwSize);
            if(!pKeyInfo)
                AfxMessageBox("Error Allocating Memory");

            // Get the key info structure.
            fReturnFlag = CertGetCertificateContextProperty(
                          pCertContext,
                          CERT_KEY_PROV_INFO_PROP_ID,
                          pKeyInfo,
                          &dwSize);

            // Does it have a signature key?
            if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
            {
                AfxMessageBox("Signature Cert Found");
                fTestFlag = TRUE;
                break;
            }

        }
        pPrevCertContext = pCertContext;
    }
    CertFreeCertificateContext(pPrevCertContext);
    if(pKeyInfo)
        free(pKeyInfo);

    if(FALSE == fTestFlag)
    {
        AfxMessageBox("Signature Cert Not Found");
        return NULL;
    }else
        return (pCertContext);
}


Enveloped Data

This data type consists of encrypted content of any type and encrypted content-encryption keys for one or more recipients. This type of message should be used when you want to keep the contents of the message secret and to allow only specified persons or entities to retrieve the contents.


Encoding Enveloped Data

The tasks required to encode an enveloped message are depicted in the following illustration and described in the list that follows it.

The sequence of events for encoding enveloped data, as depicted in the previous illustration, is as follows:

  1. A pointer to the plaintext message is retrieved.
  2. A symmetric (session) key is generated.
  3. The symmetric key and specified encryption algorithm are used to encrypt the message data.
  4. A certificate store is opened.
  5. The recipient's certificate is retrieved from the store.
  6. The public key is retrieved from the recipient's certificate.
  7. Using the recipient's public key, the symmetric key is encrypted.
  8. From the recipients certificate, the recipient's ID is retrieved.
  9. The following information is included in the digitally enveloped message: the data encryption algorithm, the encrypted data, the encrypted symmetric key, and the recipient information structure.

To use low-level message functions to accomplish the tasks just listed, use the following procedure.

To encode an enveloped message using CryptoAPI
  1. Create or retrieve the content.
  2. Get a cryptographic provider.
  3. Get a recipient certificate.
  4. Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.
  5. Call CryptMsgCalculateEncodedLength to get the size of the encoded message blob. Allocate memory for it.
  6. Call CryptMsgOpenToEncode passing in CMSG_ENVELOPED for dwMsgType, and a pointer to CMSG_ENVELOPED_ENCODE_INFO for pvMsgEncodeInfo. As a result of this call, you will get a handle to the opened message.
  7. Call CryptMsgUpdate passing in the handle retrieved in step 6, and a pointer to the data that is to be encrypted, enveloped, and encoded. This function can be called as many times as necessary to complete the encoding process.
  8. Call CryptMsgGetParam, passing in the handle retrieved in step 6, and the appropriate parameter types to access the desired, encoded data. For example, pass in CMSG_CONTENT_PARAM to get a pointer to the entire PKCS #7 message.

    If the result of this encoding is to be used as the inner data for another encoded message, such as an enveloped message, the CMSG_BARE_CONTENT_PARAM parameter must be passed. For example code showing this, see Enveloped Message Example 2.

  9. Close the message by calling CryptMsgClose.

The result of this procedure is an encoded message that contains the encrypted data, the symmetric key that is encrypted with the recipient's public keys, and the recipient info data structures. The combination of encrypted content and an encrypted symmetric key for a recipient is a digital envelope for that recipient. Any type of content can be enveloped for multiple recipients.


Decoding Enveloped Data

The general tasks required to decode an enveloped message are depicted in the following illustration and described in the list that follows it.

The sequence of events for decoding enveloped data, as depicted in the previous illustration, is as follows:

  1. A pointer to the digitally enveloped message is retrieved.
  2. A certificate store is opened.
  3. From the message, the recipient ID (My ID) is retrieved.
  4. The recipient ID is used to retrieve the certificate.
  5. The private key from the certificate is retrieved.
  6. The private key is used to decrypt the symmetric (session) key.
  7. The encryption algorithm is retrieved from the message.
  8. Using the private key and encryption algorithm, the data is decrypted.

To use low-level message functions to accomplish the tasks just listed, use the following procedure.

To decode an enveloped message using the CryptoAPI
  1. Get a pointer to the encoded blob.
  2. Call CryptMsgOpenToDecode, passing the necessary arguments.
  3. Call CryptMsgUpdate once, passing in the handle retrieved in step 2, and a pointer to the data that is to be decoded. This causes the appropriate actions to be taken on the message, depending on the message type.
  4. Call CryptMsgGetParam, passing in the handle retrieved in step 2, and CMSG_TYPE_PARAM to verify that the message is of the enveloped data type.
  5. Again call CryptMsgGetParam, passing in CMSG_INNER_CONTENT_TYPE_PARAM, to get the data type of the inner content.
  6. If the inner content data type is data, proceed to decrypt and decode the content. Otherwise, run a decode procedure appropriate for the content data type.
  7. Assuming the inner content type is "data", initialize the CMSG_CTRL_DECRYPT_PARA data structure, and call CryptMsgControl, passing in CMSG_CTRL_DECRYPT and the address of the structure. The content will be decrypted.
  8. Call CryptMsgGetParam, passing in CMSG_CONTENT_PARAM to get a pointer to the decoded content data blob (BYTE string).
  9. Call CryptMsgClose to close the message.

The result of this procedure is that the message was decoded and decrypted, and a pointer was retrieved to the content data blob.


Enveloped Message Example 1

The following example code demonstrates the process of encoding, decoding, and decrypting an enveloped message that has a data inner-content data type.

//=============================================================
// EXAMPLE CODE FOR CREATING AN ENVELOPED MESSAGE.
//=============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// the content will usually exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                        "Enveloped Message";      // The message
char* pszContent = szContent;                     // A string pointer
BYTE* pbContent = (BYTE*) pszContent;             // A byte pointer
DWORD cbContent = sizeof(szContent);              // Size of message

AfxMessageBox(pszContent);    // Display the messge

//-------------------------------------------------------------
// Get a handle to a crytographic provider.
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
               &hCryptProv,       // Address for handle to be returned
               NULL,              // Use the current user's logon name
               NULL,              // Use the default provider
               PROV_RSA_FULL,     // Specifies the provider type
               0);                // Zero allows access to private keys
if(!fReturn)
{
    AfxMessageBox("CryptAcquireContext failed");
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to the recipient certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pRecipCert = NULL;

// For the implementation of GetRecipientCert(), see the function
// at the end of this example code.
pRecipCert = GetRecipientCert(hStoreHandle, "James Allard");
if(!pRecipCert)
{
    AfxMessageBox( "Error Getting Recipient Cert");
    return;
}

// Create an array of CERT_INFOs. In this example, a single
// recipient.
PCERT_INFO        RecipCertArray[1];
RecipCertArray[0] = pRecipCert->pCertInfo;

//-------------------------------------------------------------
// Initialize the symmetric encryption Algorithm Identifier
// structure.
//-------------------------------------------------------------
DWORD                        ContentEncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER   ContentEncryptAlgorithm;
ContentEncryptAlgSize = sizeof(ContentEncryptAlgorithm);
memset(&ContentEncryptAlgorithm, 0,
                             ContentEncryptAlgSize); // Init. to zero.

// Set the necessary fields. This particular OID doesn't
// need any parameters. Some OIDs, however will need the
// parameters member to be initialized.
ContentEncryptAlgorithm.pszObjId = szOID_RSA_RC4;

//-------------------------------------------------------------
// Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_ENVELOPED_ENCODE_INFO    EnvelopedEncodeInfo;

memset(&EnvelopedEncodeInfo, 0,
                        sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvelopedEncodeInfo.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvelopedEncodeInfo.hCryptProv = hCryptProv;
EnvelopedEncodeInfo.ContentEncryptionAlgorithm =
                                        ContentEncryptAlgorithm;
EnvelopedEncodeInfo.pvEncryptionAuxInfo = NULL;
EnvelopedEncodeInfo.cRecipients = 1;
EnvelopedEncodeInfo.rgpRecipients = RecipCertArray;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbEncodedBlob;
BYTE        *pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                    MY_ENCODING_TYPE,         // Msg encoding type
                    0,                        // Flags
                    CMSG_ENVELOPED,           // Msg type
                    &EnvelopedEncodeInfo,     // Ptr. to struct.
                    NULL,                     // Inner content ObjID
                    cbContent);               // size of content
if(0 == cbEncodedBlob)
{
    AfxMessageBox("Getting cbEncodedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    AfxMessageBox("Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
                MY_ENCODING_TYPE,        // Encoding type
                0,                       // Flags
                CMSG_ENVELOPED,          // Msg type
                &EnvelopedEncodeInfo,    // Pointer to structure
                NULL,                    // Inner content ObjID.
                NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("OpenToEncode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
                    hMsg,         // Handle to the message
                    pbContent,    // Pointer to the content
                    cbContent,    // Size of the content
                    TRUE);        // Last call
if(!fResult)
{
    AfxMessageBox("MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
                  hMsg,                  // Handle to the message
                  CMSG_CONTENT_PARAM,    // Parameter type
                  0,                     // Index
                  pbEncodedBlob,         // Pointer to the blob
                  &cbEncodedBlob);       // Size of the blob
if(!fResult)
{
    AfxMessageBox("MsgGetParam failed");
    free(pbEncodedBlob);
    return;
}else
    AfxMessageBox("Message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, enveloped content.

BOOL fForceFlag = 0;
BOOL fAllCertsClosed = 1;
// If CERT_CLOSE_STORE_FORCE_FLAG is used with CertCloseStore,
// all open certificate contexts are closed and freed, and
// the store is closed. In some cases, such as multi-
// threaded programs, this may not be desirable. If
// CERT_CLOSE_STORE_CHECK_FLAG is used instead, the store will
// close but will warn you if all of the opened or duplicated
// certificate contexts have not been closed. Use
// CertFreeCertificateContext to close them when appropriate (as
// demonstrated in the "else" section of the following code).
if(fForceFlag)
{
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
}
else
{
    CertFreeCertificateContext(pRecipCert);
    fAllCertsClosed = CertCloseStore(hStoreHandle,
                                CERT_CLOSE_STORE_CHECK_FLAG);
    if(!fAllCertsClosed)
        AfxMessageBox("Certs are still open");
    CryptMsgClose(hMsg);
}

//=============================================================
// EXAMPLE CODE FOR DECODING AN ENVELOPED MESSAGE
//=============================================================

//-------------------------------------------------------------
// Open a message for decoding.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToDecode(
               MY_ENCODING_TYPE,       // Encoding type
               0,                      // Flags
               0,                      // Message type (get from msg.)
               hCryptProv,             // Cryptographic provider
               NULL,                   // Recipient info
               NULL);                  // Stream info
if(NULL == hMsg)
{
    AfxMessageBox("OpenToDecode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the encoded blob, using the data
// that was encoded in the previous section of code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                  hMsg,                 // Handle to the message
                  pbEncodedBlob,        // Pointer to the encoded blob
                  cbEncodedBlob,        // Size of the encoded blob
                  TRUE);                // Last call
if(!fResult)
{
    AfxMessageBox("Decode MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the message type.
//-------------------------------------------------------------
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType = 0;

fResult = CryptMsgGetParam(
                  hMsg,                   // Handle to the message
                  CMSG_TYPE_PARAM,        // Parameter type
                  0,                      // Index
                  &dwMsgType,             // Address for returned info
                  &cbData);               // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_TYPE_PARAM failed");
    free(pbEncodedBlob);
    return;
}

// Some applications may need to use a "switch" statement here
// and process the message differently, depending on the
// message type.
if(dwMsgType != CMSG_ENVELOPED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of inner content type BYTE string. If there is
// prior knowledge of inner data type, the next two function
// calls and the tests for the inner content type can be
// eliminated, and the decoding for that type of inner content
// can be implemented directly.
//-------------------------------------------------------------
DWORD   cbInnerContentObjId = sizeof(DWORD);

fResult = CryptMsgGetParam(
           hMsg,                          // Handle to the message
           CMSG_INNER_CONTENT_TYPE_PARAM, // Parameter type
           0,                             // Index
           NULL,                          // Address for returned info
           &cbInnerContentObjId);         // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_INNER_CONTENT_TYPE_PARAM failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Allocate memory for the string.
//-------------------------------------------------------------
PBYTE   pbInnerContentObjId = NULL;

pbInnerContentObjId = (PBYTE) malloc(cbInnerContentObjId);
if(NULL == pbInnerContentObjId)
{
    AfxMessageBox("Decode inner content malloc failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the inner content type.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
           hMsg,                          // Handle to the message
           CMSG_INNER_CONTENT_TYPE_PARAM, // Parameter type
           0,                             // Index
           pbInnerContentObjId,           // Address for returned info
           &cbInnerContentObjId);         // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_INNER_CONTENT_TYPE_PARAM #2 failed");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Process according to the inner content type.
//-------------------------------------------------------------
LPSTR    pszInnerContentObjId = (LPSTR) pbInnerContentObjId;

// Test for the "data" data type.
if(!strcmp(pszInnerContentObjId, szOID_RSA_data))
{
    //-----------------------------------------------------------
    // Initialize the CMSG_CONTROL_DECRYPT_PARA structure.
    //-----------------------------------------------------------
    CMSG_CTRL_DECRYPT_PARA DecryptPara;

    memset(&DecryptPara, 0, sizeof(CMSG_CTRL_DECRYPT_PARA));
    DecryptPara.cbSize = sizeof(CMSG_CTRL_DECRYPT_PARA);
    DecryptPara.hCryptProv = hCryptProv; // Using handle opened in
                                         //   "encode" code sect.
    DecryptPara.dwKeySpec = AT_KEYEXCHANGE;
    DecryptPara.dwRecipientIndex = 0;

    //-----------------------------------------------------------
    // Decrypt the enveloped message.
    //-----------------------------------------------------------
    fResult = CryptMsgControl(
                 hMsg,                 // Message handle
                 0,                    // Flags
                 CMSG_CTRL_DECRYPT,    // Control type
                 &DecryptPara);        // Address of the parameters
    if(!fResult)
    {
    AfxMessageBox("Decode decryption failed");
    free(pbEncodedBlob);
    return;
    }

    //-----------------------------------------------------------
    // Get the size of the content.
    //-----------------------------------------------------------
    DWORD    cbDecoded = 0;

    fResult = CryptMsgGetParam(
                  hMsg,                   // Handle to the message
                  CMSG_CONTENT_PARAM,     // Parameter type
                  0,                      // Index
                  NULL,                   // Address for returned info
                  &cbDecoded);            // Size of the returned info
    if(!fResult)
    {
    AfxMessageBox("Decode CMSG_CONTENT_PARAM failed");
    free(pbEncodedBlob);
    return;
    }

    //-----------------------------------------------------------
    // Allocate Memory.
    //-----------------------------------------------------------
    BYTE    *pbDecoded = NULL;

    pbDecoded = (BYTE *) malloc(cbDecoded);
    if(NULL == pbDecoded)
    {
    AfxMessageBox("Decode memory allocation failed");
    free(pbEncodedBlob);
    return;
    }

    //-----------------------------------------------------------
    // Get a pointer to the content.
    //-----------------------------------------------------------
    LPSTR    pDecodedString;

    fResult = CryptMsgGetParam(
                 hMsg,                   // Handle to the message
                 CMSG_CONTENT_PARAM,     // Parameter type
                 0,                      // Index
                 pbDecoded,              // Address for returned info
                 &cbDecoded);            // Size of the returned info
    if(!fResult)
    {
        AfxMessageBox("Decode CMSG_CONTENT_PARAM #2 failed");
        free(pbEncodedBlob);
        free(pbDecoded);
        return;
    }else
        AfxMessageBox("Message decoded successfully");

    pDecodedString = (LPSTR) pbDecoded;

    AfxMessageBox(pDecodedString);

    free(pbDecoded);
}
// Test for the "signed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_signedData))
{
    // Decode the "signed" data type here.
    AfxMessageBox("Signed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "enveloped" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_envelopedData))
{
    // Decode the "enveloped" data type here.
    AfxMessageBox("Enveloped data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "hashed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_digestedData))
{
    // Decode the "hashed" data type here.
    AfxMessageBox("Hashed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Clean up.
//-------------------------------------------------------------
free(pbEncodedBlob);
free(pbInnerContentObjId);
CryptMsgClose(hMsg);

}

//************************************************************
// GetRecipientCert() - A function to return the first
// certificate in the store that contains the subject name
// string passed in pszRecipName.
//************************************************************
PCCERT_CONTEXT GetRecipientCert(HCERTSTORE hCertStore,
                                            LPSTR pszRecipName)
{
    PCCERT_CONTEXT    pPrevCertContext = NULL;
    PCCERT_CONTEXT    pCertContext = NULL;
    BOOL              fTestFlag;

    // This example code will find the first occurrence of a
    // certificate containing a subject name passed in to
    // pszRecipName. That certificate must contain an exchange public
    // key (not a signature public key).  If you suspect that more
    // than one certificate exists for the desired individual, then
    // additional checking must be done to determine that the returned
    // certificate contains an exchange public key.

    while(TRUE)
    {
        pCertContext = CertFindCertificateInStore(
                        hCertStore,
                        X509_ASN_ENCODING,
                        0,
                        CERT_FIND_SUBJECT_STR_A,
                        pszRecipName,
                        pPrevCertContext);
        if(!pCertContext)
        {
            fTestFlag = FALSE;    // No match found
            break;
        }
        else
        {
            fTestFlag = TRUE;        // Match found.
            break;
        }
        pPrevCertContext = pCertContext;
    }
    CertFreeCertificateContext(pPrevCertContext);

    if(!fTestFlag)
    {
        AfxMessageBox("Recipient Cert Not Found");
        return NULL;
    }else
        return (pCertContext);
}


Enveloped Message Example 2

The following example code demonstrates the process of encoding a signed message, using that signed message as the inner-content for an enveloped message, and finally, testing the inner-content of the enveloped message to determine its inner-content type in preparation for decoding.

//=============================================================
// EXAMPLE CODE FOR CREATING A "BARE" SIGNED MESSAGE.
//=============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// the content will usually exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                        "Signed Message";        // The data
char* pszContent = szContent;                    // A string pointer
BYTE* pbContent = (BYTE*) pszContent;            // A byte pointer
DWORD cbContent = sizeof(szContent);             // Size of message

AfxMessageBox(pszContent);    // Display original message

//-------------------------------------------------------------
// Get a handle to a cryptographic provider.
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL;         // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
              &hCryptProv,       // Address for handle to be returned
              NULL,              // Use the current user's logon name
              NULL,              // Use the default provider
              PROV_RSA_FULL,     // Specifies the provider type
              0);                // Zero allows access to private keys
if(!fReturn)
{
    AfxMessageBox("CryptAcquireContext failed");
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to your signature certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pSignerCert = NULL;

// For the implementation of GetMySignerCert(), see the function
// at the end of the example code in the "Signed Data" section
// of this chapter.
pSignerCert = GetMySignerCert(hStoreHandle);
if(!pSignerCert)
{
    AfxMessageBox( "Error Getting Signer Cert");
    return;
}

//-------------------------------------------------------------
// Initialize the Algorithm Identifier struct.
//-------------------------------------------------------------
DWORD                        HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);     // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;     // Then set the
                                            //   necessary field.

//-------------------------------------------------------------
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO    SignerEncodeInfo;

memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;

// Create an array of one. NOTE: Currently, there can be only one
// signer.
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
SignerEncodeInfoArray[0] = SignerEncodeInfo;

//-------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.
//-------------------------------------------------------------
CERT_BLOB    SignerCertBlob;

SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;

// Create an array of one. Only one certificate is included.
CERT_BLOB    SignerCertBlobArray[1];
SignerCertBlobArray[0] = SignerCertBlob;

CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;

memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded = 1;
SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbSignedBlob;
BYTE        *pbSignedBlob = NULL;

    cbSignedBlob = CryptMsgCalculateEncodedLength(
                        MY_ENCODING_TYPE,       // Msg encoding type
                        0,                      // Flags
                        CMSG_SIGNED,            // Msg type
                        &SignedMsgEncodeInfo,   // Pointer to
                                                //   structure
                        NULL,                   // Inner content ObjID
                        cbContent);             // Size of content
if(0 == cbSignedBlob)
{
    AfxMessageBox("Getting cbSignedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbSignedBlob = (BYTE *) malloc(cbSignedBlob);
if(NULL == pbSignedBlob)
{
    AfxMessageBox("Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
            MY_ENCODING_TYPE,        // Encoding type
            0,                       // Flags
            CMSG_SIGNED,             // Msg type
            &SignedMsgEncodeInfo,    // Pointer to structure
            NULL,                    // Inner content ObjID
            NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("OpenToEncode Envelope failed");
    free(pbSignedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
               hMsg,            // Handle to the message
               pbContent,       // Pointer to the unsigned content
               cbContent,       // Size of the unsigned content
               TRUE);           // Last call
if(!fResult)
{
    AfxMessageBox("Encode Enveloped MsgUpdate failed");
    free(pbSignedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
               hMsg,                       // Handle to the message
               CMSG_BARE_CONTENT_PARAM,    // Parameter type
               0,                          // Index
               pbSignedBlob,               // Pointer to signed
                                           //   data blob
               &cbSignedBlob);             // Size of the blob
if(!fResult)
{
    AfxMessageBox("MsgGetParam failed");
    free(pbSignedBlob);
    CryptMsgClose(hMsg);
    return;
}else
    AfxMessageBox("Signed message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.

CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);

//=============================================================
// EXAMPLE CODE FOR ENVELOPING A SIGNED MESSAGE.
//=============================================================

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "Friend");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to the recipient certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pRecipCert = NULL;
LPSTR             pszRecipientName = "James Allard";

// For the implementation of GetRecipientCert(), see the function
// at the end of the example code in the "Enveloped Message Example
// 2" section of this chapter.
pRecipCert = GetRecipientCert(hStoreHandle, pszRecipientName);
if(!pRecipCert)
{
    AfxMessageBox( "Error Getting Recipient Cert");
    return;
}

// Create an array of CERT_INFOs. In this example there is only a
// single recipient.
PCERT_INFO        RecipCertArray[1];
RecipCertArray[0] = pRecipCert->pCertInfo;

//-------------------------------------------------------------
// Initialize the symmetric encryption Algorithm Identifier
// structure.
//-------------------------------------------------------------
DWORD                         ContentEncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    ContentEncryptAlgorithm;
ContentEncryptAlgSize = sizeof(ContentEncryptAlgorithm);
memset(&ContentEncryptAlgorithm, 0,
                        ContentEncryptAlgSize); // Init. to zero.

// Set the necessary fields. This particular OID doesn't
// need any parameters. Some OIDs, however will need the
// parameter's member to be initialized.
ContentEncryptAlgorithm.pszObjId = szOID_RSA_RC4;

//-------------------------------------------------------------
// Initialize the CMSG_ENVELOPED_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_ENVELOPED_ENCODE_INFO    EnvelopedEncodeInfo;

memset(&EnvelopedEncodeInfo, 0,
                        sizeof(CMSG_ENVELOPED_ENCODE_INFO));
EnvelopedEncodeInfo.cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
EnvelopedEncodeInfo.hCryptProv = hCryptProv;
EnvelopedEncodeInfo.ContentEncryptionAlgorithm =
                                        ContentEncryptAlgorithm;
EnvelopedEncodeInfo.pvEncryptionAuxInfo = NULL;
EnvelopedEncodeInfo.cRecipients = 1;
EnvelopedEncodeInfo.rgpRecipients = RecipCertArray;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbEncodedBlob;
BYTE        *pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                     MY_ENCODING_TYPE,        // Msg encoding type
                     0,                       // Flags
                     CMSG_ENVELOPED,          // Msg type
                     &EnvelopedEncodeInfo,    // Ptr. to struct.
                     szOID_RSA_signedData,    // Inner content ObjID
                     cbSignedBlob);           // size of content
if(0 == cbEncodedBlob)
{
    AfxMessageBox("Getting Enveloped cbEncodedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    AfxMessageBox("Enveloped Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToEncode(
            MY_ENCODING_TYPE,        // Encoding type
            0,                       // Flags
            CMSG_ENVELOPED,          // Msg type
            &EnvelopedEncodeInfo,    // Pointer to structure
            szOID_RSA_signedData,    // Inner content ObjID
            NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("Enveloped OpenToEncode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------

fResult = CryptMsgUpdate(
               hMsg,              // Handle to the message
               pbSignedBlob,      // Pointer to the signed data blob
               cbSignedBlob,      // Size of the data blob
               TRUE);             // Last call
if(!fResult)
{
    AfxMessageBox("Enveloped MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
               hMsg,                  // Handle to the message
               CMSG_CONTENT_PARAM,    // Parameter type
               0,                     // Index
               pbEncodedBlob,         // Pointer to the enveloped,
                                      //   signed data blob
               &cbEncodedBlob);       // Size of the blob
if(!fResult)
{
    AfxMessageBox("Enveloped MsgGetParam failed");
    free(pbEncodedBlob);
    return;
}else
    AfxMessageBox("Enveloped message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, enveloped, signed content.

BOOL fForceFlag = 0;
BOOL fAllCertsClosed = 1;
// If CERT_CLOSE_STORE_FORCE_FLAG is used with CertCloseStore,
// all open certificate contexts are closed and freed, and
// the store is closed. In some cases, such as multi-
// threaded programs, this may not be desirable. If
// CERT_CLOSE_STORE_CHECK_FLAG is used instead, the store will
// close but will warn you if all of the opened or duplicated
// certificate contexts have not been closed. Use
// CertFreeCertificateContext to close them when appropriate (as
// demonstrated in the "else" section of the following code).
if(fForceFlag)
{
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
}
else
{
    CertFreeCertificateContext(pRecipCert);
    fAllCertsClosed = CertCloseStore(hStoreHandle,
                                CERT_CLOSE_STORE_CHECK_FLAG);
    if(!fAllCertsClosed)
        AfxMessageBox("Certs are still open");
    CryptMsgClose(hMsg);
}

//=============================================================
// EXAMPLE CODE FOR DECODING AN ENVELOPED MESSAGE
//=============================================================

//-------------------------------------------------------------
// Open a message for decoding.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToDecode(
            MY_ENCODING_TYPE,       // Encoding type
            0,                      // Flags
            0,                      // Message type (get from msg.)
            hCryptProv,             // Cryptographic provider
            NULL,                   // Recipient info
            NULL);                  // Stream info
if(NULL == hMsg)
{
    AfxMessageBox("OpenToDecode Enveloped message failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the encoded blob, using the data
// that was encoded in the previous section of code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
               hMsg,                 // Handle to the message
               pbEncodedBlob,        // Pointer to the encoded, signed
                                     //   data blob
               cbEncodedBlob,        // Size of the encoded blob
               TRUE);                // Last call
if(!fResult)
{
    AfxMessageBox("Enveloped Decode MsgUpdate failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the message type.
//-------------------------------------------------------------
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType = 0;

fResult = CryptMsgGetParam(
               hMsg,               // Handle to the message
               CMSG_TYPE_PARAM,    // Parameter type
               0,                  // Index
               &dwMsgType,         // Address for returned info
               &cbData);           // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Enveloped Decode CMSG_TYPE_PARAM failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    return;
}

// Some applications may need to use a "switch" statement here
// and process the message differently, depending on the
// message type.
if(dwMsgType != CMSG_ENVELOPED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of inner content type BYTE string. If there is
// prior knowledge of inner data type, the next two function
// calls and the tests for the inner content type can be
// eliminated, and the decoding for that type of inner content
// can be implemented directly.
//-------------------------------------------------------------
DWORD   cbInnerContentObjId = sizeof(DWORD);

fResult = CryptMsgGetParam(
           hMsg,                          // Handle to the message
           CMSG_INNER_CONTENT_TYPE_PARAM, // Parameter type
           0,                             // Index
           NULL,                          // Address for returned info
           &cbInnerContentObjId);         // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_INNER_CONTENT_TYPE_PARAM failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Allocate memory for the string.
//-------------------------------------------------------------
PBYTE   pbInnerContentObjId = NULL;

pbInnerContentObjId = (PBYTE) malloc(cbInnerContentObjId);
if(NULL == pbInnerContentObjId)
{
    AfxMessageBox("Decode inner content malloc failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the inner content type.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
           hMsg,                          // Handle to the message
           CMSG_INNER_CONTENT_TYPE_PARAM, // Parameter type
           0,                             // Index
           pbInnerContentObjId,           // Address for returned info
           &cbInnerContentObjId);         // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_INNER_CONTENT_TYPE_PARAM #2 failed");
    free(pbSignedBlob);
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Process according to the inner content type.
//-------------------------------------------------------------
LPSTR    pszInnerContentObjId = (LPSTR) pbInnerContentObjId;

// Test for the "data" data type.
if(!strcmp(pszInnerContentObjId, szOID_RSA_data))
{
    // Decode the "data" data type here.
    AfxMessageBox("Data data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;

}
// Test for the "signed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_signedData))
{
    // Decode the signed data type here.
    AfxMessageBox("Signed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "enveloped" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_envelopedData))
{
    // Decode the enveloped data type here.
    AfxMessageBox("Enveloped data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}
// Test for the "hashed" data type.
else if(!strcmp(pszInnerContentObjId, szOID_RSA_digestedData))
{
    // Decode the hashed data type here.
    AfxMessageBox("Hashed data type");
    free(pbEncodedBlob);
    free(pbInnerContentObjId);
    return;
}

//-------------------------------------------------------------
// Clean up.
//-------------------------------------------------------------
free(pbSignedBlob);
free(pbEncodedBlob);
free(pbInnerContentObjId);
CryptMsgClose(hMsg);

}


Hashed Data

This data type consists of content of any type and a hash of the content. It can be used when it is only necessary to confirm that the message content has not been modified since the hash was created.


Encoding Hashed Data

When creating a hashed message, there can be multiple hash algorithms and multiple hashes. The following illustration depicts the tasks required to encode a hashed message and the tasks are described in the list that follows it.

To create a hashed message
  1. Get a pointer to the data to be hashed.
  2. Determine the hash algorithm to be used.
  3. Put the data through a hashing function using the hash algorithm.
  4. Include the original data to be hashed, the hashing algorithms, and the hashes in the encoded message.

To use low-level message functions to accomplish the tasks just outlined, use the following procedure.

To encode a hashed message using CryptoAPI
  1. Create or retrieve the content.
  2. Get a cryptographic provider.
  3. Initialize the CMSG_HASHED_ENCODE_INFO structure.
  4. Call CryptMsgCalculateEncodedLength to get the size of the encoded message blob. Allocate memory for it.
  5. Call CryptMsgOpenToEncode passing in CMSG_HASHED for dwMsgType, and a pointer to CMSG_HASHED_ENCODE_INFO for pvMsgEncodeInfo. As a result of this call, you get a handle to the opened message.
  6. Call CryptMsgUpdate, passing in the handle retrieved in step 5, and a pointer to the data that is to be hashed and encoded. This function can be called as many times as necessary to complete the encoding process.
  7. Call CryptMsgGetParam, passing in the handle retrieved in step 5, and the appropriate parameter types to access the desired, encoded data. For example, pass in CMSG_CONTENT_PARAM to get a pointer to the entire PKCS #7 message.

    If the result of this encoding is to be used as the inner data for another encoded message, such as an enveloped message, the CMSG_BARE_CONTENT_PARAM parameter must be passed. For example code showing this, see Enveloped Message Example 2.

  8. Close the message by calling CryptMsgClose.

The result of this procedure is an encoded message that contains the original data, the hashing algorithms, and the hash of that data. A pointer to the encoded message blob is obtained in step 7.


Decode Hashed Data

The following two procedures allow you to decode and then verify hashed data.

To decode hashed data
  1. Get a pointer to the encoded blob.
  2. Call CryptMsgOpenToDecode, passing the necessary arguments.
  3. Call CryptMsgUpdate once, passing in the handle retrieved in step 2, and a pointer to the data that is to be decoded. This causes the appropriate actions to be taken on the message, depending on the message type.
  4. Call CryptMsgGetParam, passing in the handle retrieved in step 2, and the appropriate parameter types to access the desired, decoded data. For example, pass in CMSG_CONTENT_PARAM to get a pointer to the decoded content.
To verify the hash
  1. Call CryptMsgControl, passing in CMSG_CTRL_VERIFY_HASH to verify the hashes.
  2. Call CryptMsgClose to close the message.


Hashed Message Example Code

The following example code demonstrates the process of encoding, decoding, and verifying the hash of a hashed message.

//=============================================================
// EXAMPLE CODE FOR CREATING A HASHED MESSAGE.
//=============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// the content will usually exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                        "Hashed Message";    // The message
char* pszContent = szContent;                // A string pointer
BYTE* pbContent = (BYTE*) pszContent;        // A byte pointer
DWORD cbContent = sizeof(szContent);         // Size of message

AfxMessageBox(pszContent);    // Display original message.

//-------------------------------------------------------------
// Get a handle to a cryptographic provider.
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
               &hCryptProv,      // Address for the handle
               NULL,             // Use the current user's logon name
               NULL,             // Use the default provider
               PROV_RSA_FULL,    // Specifies the provider type
               0);               // Zero allows access to private keys
if(!fReturn)
{
    AfxMessageBox("CryptAcquireContext failed");
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure.
//-------------------------------------------------------------
DWORD                        HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);   // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;   // Then set the
                                          //   necessary field.

//-------------------------------------------------------------
// Initialize the CMSG_HASHED_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_HASHED_ENCODE_INFO    HashedEncodeInfo;

memset(&HashedEncodeInfo, 0, sizeof(CMSG_HASHED_ENCODE_INFO));
HashedEncodeInfo.cbSize = sizeof(CMSG_HASHED_ENCODE_INFO);
HashedEncodeInfo.hCryptProv = hCryptProv;
HashedEncodeInfo.HashAlgorithm = HashAlgorithm;
HashedEncodeInfo.pvHashAuxInfo = NULL;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD        cbEncodedBlob;
BYTE        *pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                     MY_ENCODING_TYPE,     // Msg encoding type
                     0,                    // Flags
                     CMSG_HASHED,          // Msg type
                     &HashedEncodeInfo,    // Ptr. to struct.
                     NULL,                 // Inner content ObjID
                     cbContent);           // size of content
if(0 == cbEncodedBlob)
{
    AfxMessageBox("Getting cbEncodedBlob length failed");
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    AfxMessageBox("Malloc failed");
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
            MY_ENCODING_TYPE,        // Encoding type
            0,                       // Flags
            CMSG_HASHED,             // Msg type
            &HashedEncodeInfo,       // Pointer to structure
            NULL,                    // Inner content ObjID
            NULL);                   // Stream Info (not used)
if(NULL == hMsg)
{
    AfxMessageBox("OpenToEncode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
                    hMsg,          // Handle to the message
                    pbContent,     // Pointer to the content
                    cbContent,     // Size of the content
                    TRUE);         // Last call
if(!fResult)
{
    AfxMessageBox("MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
               hMsg,                     // Handle to the message
               CMSG_CONTENT_PARAM,       // Parameter type
               0,                        // Index
               pbEncodedBlob,            // Pointer to the blob
               &cbEncodedBlob);          // Size of the blob
if(!fResult)
{
    AfxMessageBox("MsgGetParam failed");
    free(pbEncodedBlob);
    return;
}else
    AfxMessageBox("Message encoded sucessfully");

// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.

CryptMsgClose(hMsg);

//=============================================================
// EXAMPLE CODE FOR DECODING A HASHED MESSAGE
//=============================================================

//-------------------------------------------------------------
// Open a message for decoding.
//-------------------------------------------------------------

hMsg = CryptMsgOpenToDecode(
            MY_ENCODING_TYPE,         // Encoding type
            0,                        // Flags
            0,                        // Message type (get from msg.)
            hCryptProv,               // Cryptographic provider
            NULL,                     // Recipient info
            NULL);                    // Stream info
if(NULL == hMsg)
{
    AfxMessageBox("OpenToDecode failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Update the message with the encoded blob, using the data
// that was encoded in the previous section of code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                    hMsg,             // Handle to the message
                    pbEncodedBlob,    // Pointer to the encoded blob
                    cbEncodedBlob,    // Size of the encoded blob
                    TRUE);            // Last call
if(!fResult)
{
    AfxMessageBox("Decode MsgUpdate failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the message type.
//-------------------------------------------------------------
DWORD cbData = sizeof(DWORD);
DWORD dwMsgType = 0;

fResult = CryptMsgGetParam(
                    hMsg,               // Handle to the message
                    CMSG_TYPE_PARAM,    // Parameter type
                    0,                  // Index
                    &dwMsgType,         // Address for returned info
                    &cbData);           // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_TYPE_PARAM failed");
    free(pbEncodedBlob);
    return;
}

// Some applications may need to use a "switch" statement here
// and process the message differently, depending on the
// message type.
if(dwMsgType != CMSG_HASHED)
{
    AfxMessageBox("Wrong message type");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get the size of the content.
//-------------------------------------------------------------
DWORD    cbDecoded = 0;

fResult = CryptMsgGetParam(
               hMsg,                   // Handle to the message
               CMSG_CONTENT_PARAM,     // Parameter type
               0,                      // Index
               NULL,                   // Address for returned info
               &cbDecoded);            // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Allocate Memory.
//-------------------------------------------------------------
BYTE    *pbDecoded = NULL;

pbDecoded = (BYTE *) malloc(cbDecoded);
if(NULL == pbDecoded)
{
    AfxMessageBox("Decode memory allocation failed");
    free(pbEncodedBlob);
    return;
}

//-------------------------------------------------------------
// Get a pointer to the content.
//-------------------------------------------------------------
LPSTR    pDecodedString;

fResult = CryptMsgGetParam(
               hMsg,                    // Handle to the message
               CMSG_CONTENT_PARAM,      // Parameter type
               0,                       // Index
               pbDecoded,               // Address for returned info
               &cbDecoded);             // Size of the returned info
if(!fResult)
{
    AfxMessageBox("Decode CMSG_CONTENT_PARAM #2 failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}else
    AfxMessageBox("Message decoded successfully");

pDecodedString = (LPSTR) pbDecoded;

AfxMessageBox(pDecodedString);

//-------------------------------------------------------------
// VERIFY THE HASH.
//-------------------------------------------------------------

fResult = CryptMsgControl(
              hMsg,                        // Handle to the message
              0,                           // Flags
              CMSG_CTRL_VERIFY_HASH,       // Control type
              NULL);                       // Pointer not used
if(!fResult)
{
    AfxMessageBox("Verify Hash failed");
    free(pbEncodedBlob);
    free(pbDecoded);
    return;
}
else
    AfxMessageBox("Verify Hash Succeeded");

// If the call succeeded, the hash was verified and the data
// has not been tampered with.

//-------------------------------------------------------------
// Clean up
//-------------------------------------------------------------
free(pbEncodedBlob);
free(pbDecoded);
CryptMsgClose(hMsg);
}


Countersigning Signed Messages

Sometimes you may want to countersign a signed message. For example, assume that user A sends a document, in the form of a signed-data message, to user B, expecting B to confirm agreement to the terms contained in the document. User B decodes the message, reads the terms and, if in agreement, countersigns the message. The countersigned message is then sent the back to user A. User A now knows, and can prove, that user B agreed to the terms.

There are some CryptoAPI low-level message functions that assist with the countersigning process.

  • CryptMsgCountersign. Countersigns an already existing signature in a message, and adds the countersignature to the message as an unauthenticated attribute.
  • CryptMsgCountersignEncoded. Countersigns an already existing signature (encoded SignerInfo, as defined by PKCS # 7) in a message. It outputs an encoded SignerInfo blob suitable for adding to a signed-data message, or a signed-and-enveloped-data message, as an unauthenticated attribute.
  • CryptMsgVerifyCountersignatureEncoded. Verifies a countersignature at the SignerInfo level. It verifies that a retrieved countersignature attribute contains the encrypted hash of the encryptedDigest field of the original SignerInfo.

Note Although the syntax of these functions allows for multiple countersigners, only a single countersigner is currently supported.

To countersign a signed message by using CryptMsgCountersign
  1. Call CryptMsgOpenToDecode to get a handle to the signed message.
  2. Initialize a PCMSG_SIGNER_ENCODE_INFO structure for the countersigner.
  3. Add the PCMSG_SIGNER_ENCODE_INFO structure to an array of countersigners (only one countersigner is currently supported).
  4. Call CryptMsgCountersign to add the countersignature(s).

If the function call succeeds, the original message now has a countersignature included as an unauthenticated attribute.

To countersign a signed message by using CryptMsgCountersignEncoded
  1. Call CryptMsgOpenToDecode to get a handle to the signed message.
  2. Call CryptMsgGetParam to retrieve the encoded SignerInfo of the signed message.
  3. Initialize a PCMSG_SIGNER_ENCODE_INFO structure for the countersigner.
  4. Add PCMSG_SIGNER_ENCODE_INFO structure to an array of countersigners (only one countersigner is currently supported).
  5. Call CryptMsgCountersignEncoded to create the encoded countersignature attribute.
  6. Call CryptMsgControl to add the countersignature attribute to the original message as an unauthenticated attribute.

If all of the function calls succeed, a countersignature attribute was added to the original message.

To Verify a Countersignature
  1. Call CryptMsgOpenToDecode to get a handle to the signed message.
  2. Get a pointer to the countersigner's certificate (PCERT_INFO).
  3. Call CryptMsgGetParam to retrieve the SignerInfo from the message.
  4. Call CryptMsgGetParam to retrieve the Countersignature from the message.
  5. Call CryptMsgVerifyCountersignatureEncoded to verify the countersignature.

If the CryptMsgVerifyCountersignatureEncoded function call succeeds, the countersignature is verified.


Example Code For Countersigning a Message

The following example code creates a signed message, adds a countersignature to it, and then verifies the countersignature.

//===============================================================
// EXAMPLE CODE FOR CREATING A SIGNED MESSAGE, COUNTERSIGNING THE
// SIGNED MESSAGE, AND VERIFYING THE COUNTERSIGNATURE.
//===============================================================

//===============================================================
// CREATE A SIGNED MESSAGE.
//===============================================================

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | CRYPT_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message content- this code creates
// the message content and gets a pointer to it. In reality,
// usually the content will exist somewhere and a pointer to it
// will get passed to the application.
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle \n"
                    "Signed Message";        // The message
char* pszContent = szContent;                // A string pointer
BYTE* pbContent = (BYTE*) pszContent;        // A byte pointer
DWORD cbContent = sizeof(szContent);         // Size of message

// Display example name.
MessageBox(hwnd, "CryptMsgCountersign Example", NULL, MB_OK);

//-------------------------------------------------------------
// Get a handle to a cryptographic provider.
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
    &hCryptProv,        // Address for handle to be returned
    NULL,               // Use the current user's logon name
    NULL,               // Use the default provider
    PROV_RSA_FULL,      // Specifies the provider type
    0);                 // Zero allows access to private keys
if(!fReturn)
{
    MessageBox(hwnd, "CryptAcquireContext failed", NULL, MB_OK);
    return;
}

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open the system certificate store.
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    MessageBox(hwnd, "Error Getting Store Handle", NULL, MB_OK);
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to the signer's signature certificate.
//-------------------------------------------------------------
PCCERT_CONTEXT    pSignerCert = NULL;

// For the implementation of GetMySignerCert(), see the function
// at the end of this example code.
pSignerCert = GetMySignerCert(hwnd, hStoreHandle);
if(!pSignerCert)
{
    MessageBox(hwnd, "Error Getting Signer Cert", NULL, MB_OK);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    return;
}
else
    MessageBox(hwnd, "Signer's Certificate Found", NULL, MB_OK);

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure.
//-------------------------------------------------------------
DWORD                        HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER   HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);  // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;  // Then set the
                                         //   necessary field.

//-------------------------------------------------------------
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.
//-------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO    SignerEncodeInfo;

memset(&SignerEncodeInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
SignerEncodeInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
SignerEncodeInfo.pCertInfo = pSignerCert->pCertInfo;
SignerEncodeInfo.hCryptProv = hCryptProv;
SignerEncodeInfo.dwKeySpec = AT_SIGNATURE;
SignerEncodeInfo.HashAlgorithm = HashAlgorithm;
SignerEncodeInfo.pvHashAuxInfo = NULL;

// Create an array of one. NOTE: Currently, there can be only one
// signer.
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfoArray[1];
SignerEncodeInfoArray[0] = SignerEncodeInfo;

//-------------------------------------------------------------
// Initialize the CMSG_SIGNED_ENCODE_INFO structure.
//-------------------------------------------------------------
CERT_BLOB    SignerCertBlob;

SignerCertBlob.cbData = pSignerCert->cbCertEncoded;
SignerCertBlob.pbData = pSignerCert->pbCertEncoded;

// Create an array of one. Only one certificate is included.
CERT_BLOB    SignerCertBlobArray[1];
SignerCertBlobArray[0] = SignerCertBlob;

CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;

memset(&SignedMsgEncodeInfo, 0, sizeof(CMSG_SIGNED_ENCODE_INFO));
SignedMsgEncodeInfo.cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
SignedMsgEncodeInfo.cSigners = 1;
SignedMsgEncodeInfo.rgSigners = SignerEncodeInfoArray;
SignedMsgEncodeInfo.cCertEncoded = 1;
SignedMsgEncodeInfo.rgCertEncoded = SignerCertBlobArray;
SignedMsgEncodeInfo.rgCrlEncoded = NULL;

//-------------------------------------------------------------
// Get the size of the encoded message blob.
//-------------------------------------------------------------
DWORD          cbEncodedBlob;
BYTE*          pbEncodedBlob = NULL;

cbEncodedBlob = CryptMsgCalculateEncodedLength(
                   MY_ENCODING_TYPE,     // Msg encoding type
                   0,                    // Flags
                   CMSG_SIGNED,          // Msg type
                   &SignedMsgEncodeInfo, // Ptr. to struct.
                   NULL,                     // Inner content ObjID
                   cbContent);               // size of content
if(0 == cbEncodedBlob)
{
    MessageBox(hwnd, "Getting cbEncodedBlob length failed",
                NULL, MB_OK);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    return;
}

//-------------------------------------------------------------
// Allocate memory for the encoded blob.
//-------------------------------------------------------------
pbEncodedBlob = (BYTE *) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    MessageBox(hwnd, "Malloc failed", NULL, MB_OK);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    return;
}

//-------------------------------------------------------------
// Open a message to encode.
//-------------------------------------------------------------
HCRYPTMSG    hMsg = NULL;

hMsg = CryptMsgOpenToEncode(
               MY_ENCODING_TYPE,      // Encoding type
               0,                     // Flags
               CMSG_SIGNED,               // Msg type
               &SignedMsgEncodeInfo,  // Pointer to structure
               NULL,                  // Inner content ObjID
               NULL);                 // Stream Info (not used)
if(NULL == hMsg)
{
    MessageBox(hwnd, "OpenToEncode failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Update the message with the data.
//-------------------------------------------------------------
BOOL fResult;

fResult = CryptMsgUpdate(
                    hMsg,       // Handle to the message
                    pbContent,      // Pointer to the content
                    cbContent,      // Size of the content
                    TRUE);      // Last call
if(!fResult)
{
    MessageBox(hwnd, "MsgUpdate failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Get the resultant message.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
                  hMsg,                // Handle to the message
                  CMSG_CONTENT_PARAM,  // Parameter type
                  0,                   // Index
                  pbEncodedBlob,       // Pointer to the blob
                  &cbEncodedBlob);     // Size of the blob
if(!fResult)
{
    MessageBox(hwnd, "MsgGetParam failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}else
    MessageBox(hwnd, "Message successfully signed", NULL, MB_OK);

// If the call was successful, pbEncodedBlob now points to the
// encoded, signed content.

CryptMsgClose(hMsg); // The message is complete - close the handle

//===============================================================
// COUNTERSIGN THE SIGNED MESSAGE. Assume that the message just
// created was sent to the intended recipient, and that a pointer
// (pbEncodedBlob) to the message (encoded blob) has been retrieved.
// The following code will add a countersignature to the signed
// message.
//===============================================================

//---------------------------------------------------------------
// Before countersigning, the message must first be decoded.
// Open a message for decoding.
//---------------------------------------------------------------
hMsg = CryptMsgOpenToDecode(
                MY_ENCODING_TYPE,   // Encoding type
                0,                  // Flags
                0,                  // Message type (get from msg.)
                hCryptProv,             // Cryptographic provider
                NULL,               // Recipient info
                NULL);              // Stream info
if(NULL == hMsg)
{
    MessageBox(hwnd, "OpenToDecode failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Update the message with the data (encoded blob).
// In this example, pbEncodedBlob and cbEncodedBlob were
// initialized in the previous code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                hMsg,            // Handle to the message
                pbEncodedBlob,       // Pointer to the encoded blob
                cbEncodedBlob,       // Size of the encoded blob
                TRUE);           // Last call
if(!fResult)
{
    MessageBox(hwnd, "Decode MsgUpdate failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Get the size of the content.
//-------------------------------------------------------------
DWORD    cbDecoded = 0;

fResult = CryptMsgGetParam(
                hMsg,                // Handle to the message
                CMSG_CONTENT_PARAM,    // Parameter type
                0,                    // Index
                NULL,                // Address for returned info
                &cbDecoded);        // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Decode CMSG_CONTENT_PARAM failed", NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Allocate memory.
//-------------------------------------------------------------
BYTE    *pbDecoded = NULL;

pbDecoded = (BYTE *) malloc(cbDecoded);
if(NULL == pbDecoded)
{
    MessageBox(hwnd, "Decode memory allocation failed",
                   NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Get a pointer to the content.
//-------------------------------------------------------------
fResult = CryptMsgGetParam(
                hMsg,                // Handle to the message
                CMSG_CONTENT_PARAM,  // Parameter type
                0,                   // Index
                pbDecoded,           // Address for returned info
                &cbDecoded);         // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Decode CMSG_CONTENT_PARAM #2 failed",
                     NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}else
    MessageBox(hwnd, "Message decoded successfully", NULL, MB_OK);

//---------------------------------------------------------------
// Proceed with the countersigning.
//---------------------------------------------------------------

//---------------------------------------------------------------
// Initialize the CRYPT_ALGORITHM_IDENTIFIER structure. In this
// case the initialization performed for signing the message in
// the previous code is used.
//---------------------------------------------------------------

//---------------------------------------------------------------
// Get the countersigner's certificate.
//---------------------------------------------------------------
PCCERT_CONTEXT    pCntrSigCert = NULL;

// For the implementation of GetMySignerCert(), see the function
// at the end of this example code.
pCntrSigCert = GetMySignerCert(hwnd, hStoreHandle);

if(!pCntrSigCert)
{
    MessageBox(hwnd, "Couldn't Find Countersigner's "
                     "Certificate", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}
else
    MessageBox(hwnd, "Countersigner's Certificate Found",
                     NULL, MB_OK);

// If the call was successful, a pointer to the desired
// certificate now resides at pCntrSigCert.

//---------------------------------------------------------------
// Initialize the PCMSG_SIGNER_ENCODE_INFO structure.
//---------------------------------------------------------------
CMSG_SIGNER_ENCODE_INFO CountersignerInfo;

memset(&CountersignerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
CountersignerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
CountersignerInfo.pCertInfo = pCntrSigCert->pCertInfo;
CountersignerInfo.hCryptProv = hCryptProv;
CountersignerInfo.dwKeySpec = AT_SIGNATURE;
CountersignerInfo.HashAlgorithm = HashAlgorithm;

CMSG_SIGNER_ENCODE_INFO CntrSignArray[1];
CntrSignArray[0] = CountersignerInfo;

//--------------------------------------------------------------
// Countersign the message.
//--------------------------------------------------------------
fReturn = CryptMsgCountersign(
                hMsg,
                0,
                1,
                CntrSignArray);
if(!fReturn)
{
    MessageBox(hwnd, "Countersign Failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}
else
    MessageBox(hwnd, "Countersign Succeeded", NULL, MB_OK);

//---------------------------------------------------------------
// Get a pointer to the new, countersigned message blob.
//---------------------------------------------------------------

// Get the size of memory required.
fResult = CryptMsgGetParam(
                hMsg,                  // Handle to the message
                CMSG_ENCODED_MESSAGE,  // Parameter type
                0,                     // Index
                NULL,                  // Address for returned info
                &cbEncodedBlob);       // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Sizing of cbSignerInfo Failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Allocate memory.
pbEncodedBlob = (PBYTE) malloc(cbEncodedBlob);
if(NULL == pbEncodedBlob)
{
    MessageBox(hwnd, "cbSignerInfo Memory Allocation Failed",
                      NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Get the new message encoded blob.
fResult = CryptMsgGetParam(
                hMsg,                  // Handle to the message
                CMSG_ENCODED_MESSAGE,  // Parameter type
                0,                     // Index
                pbEncodedBlob,             // Address for returned info
                &cbEncodedBlob);       // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Getting pbSignerInfo failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

CryptMsgClose(hMsg); // The message is complete - close the handle

//=============================================================
// VERIFY THE COUNTERSIGNATURE. Assume that the countersigned
// message was re-encoded, and sent back to the originator, where
// it will be decoded.
//=============================================================

//---------------------------------------------------------------
// Before verifying the countersignature, the message must first
// be decoded.
//
// Open a message for decoding.
//---------------------------------------------------------------
hMsg = CryptMsgOpenToDecode(
                MY_ENCODING_TYPE,    // Encoding type
                0,                   // Flags
                0,                   // Message type (get from msg.)
                hCryptProv,              // Cryptographic provider
                NULL,                // Recipient info
                NULL);               // Stream info
if(NULL == hMsg)
{
    MessageBox(hwnd, "OpenToDecode For Verify Countersignature "
                      "Failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Update the message with the data (encoded blob).
// In this example, pbEncodedBlob and cbEncodedBlob were
// initialized in the previous code.
//-------------------------------------------------------------
fResult = CryptMsgUpdate(
                hMsg,            // Handle to the message
                pbEncodedBlob,       // Pointer to the encoded blob
                cbEncodedBlob,       // Size of the encoded blob
                TRUE);           // Last call
if(!fResult)
{
    MessageBox(hwnd, "Verify Countersignature MsgUpdate Failed",
                       NULL, MB_OK);
    free(pbEncodedBlob);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//-------------------------------------------------------------
// Get a pointer to the CERT_INFO member of countersigner's
// certificate.  In this case, the certificate retrieved in the
// previous code segment will be used (pCntrSigCert).
//-------------------------------------------------------------

//--------------------------------------------------------------
// Retrieve the SignerInfo from the message.
//--------------------------------------------------------------

// Get the size of memory required.
DWORD    cbSignerInfo = 0;

fResult = CryptMsgGetParam(
                hMsg,                  // Handle to the message
                CMSG_ENCODED_SIGNER,   // Parameter type
                0,                     // Index
                NULL,                  // Address for returned info
                &cbSignerInfo);        // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Sizing of cbSignerInfo Failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Allocate memory.
PBYTE pbSignerInfo;

pbSignerInfo = (PBYTE) malloc(cbSignerInfo);
if(NULL == pbSignerInfo)
{
    MessageBox(hwnd, "cbSignerInfo Memory Allocation Failed",
                       NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Get the message signer information.
fResult = CryptMsgGetParam(
                hMsg,                 // Handle to the message
                CMSG_ENCODED_SIGNER,  // Parameter type
                0,                    // Index
                pbSignerInfo,         // Address for returned info
                &cbSignerInfo);       // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Getting pbSignerInfo failed", NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pbSignerInfo);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//--------------------------------------------------------------
// Retrieve the CountersignerInfo from the message.
//--------------------------------------------------------------

// Get the size of memory required.
DWORD    cbCountersignerInfo = 0;
PCRYPT_ATTRIBUTES   pCountersignerInfo = NULL;

fResult = CryptMsgGetParam(
                hMsg,                    // Handle to the message
                CMSG_SIGNER_UNAUTH_ATTR_PARAM,    // Parameter type
                0,                        // Index
                NULL,                    // Address for returned info
                &cbCountersignerInfo);    // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Sizing of cbCountersignerInfo Failed",
                      NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Allocate memory.
pCountersignerInfo = (PCRYPT_ATTRIBUTES) malloc(cbCountersignerInfo);
if(NULL == pCountersignerInfo)
{
    MessageBox(hwnd, "pbCountersignInfo Memory Allocation Failed",
                      NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

// Get the message SIGNER_INFO.
fResult = CryptMsgGetParam(
                hMsg,                    // Handle to the message
                CMSG_SIGNER_UNAUTH_ATTR_PARAM,    // Parameter type
                0,                        // Index
                pCountersignerInfo,        // Address for returned info
                &cbCountersignerInfo);    // Size of the returned info
if(!fResult)
{
    MessageBox(hwnd, "Getting pbCountersignerInfo failed",
                      NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pbSignerInfo);
    free(pCountersignerInfo);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}

//---------------------------------------------------------------
// Verify the countersignature.
//---------------------------------------------------------------
fReturn = CryptMsgVerifyCountersignatureEncoded(
                hCryptProv,
                MY_ENCODING_TYPE,
                pbSignerInfo,
                cbSignerInfo,
                pCountersignerInfo->rgAttr->rgValue->pbData,
                pCountersignerInfo->rgAttr->rgValue->cbData,
                pCntrSigCert->pCertInfo);
if(!fReturn)
{
    MessageBox(hwnd, "Verify Countrsignature Failed",
                      NULL, MB_OK);
    free(pbEncodedBlob);
    free(pbDecoded);
    free(pbSignerInfo);
    free(pCountersignerInfo);
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
    CryptMsgClose(hMsg);
    return;
}
else
    MessageBox(hwnd, "Verify Countrsignature Succeeded",
                      NULL, MB_OK);

//--------------------------------------------------------------
// Clean up.
//--------------------------------------------------------------
free(pbEncodedBlob);
free(pbDecoded);
free(pbSignerInfo);
free(pCountersignerInfo);
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
CryptMsgClose(hMsg);

//************************************************************
// GetMySignerCert() - A function to list all the certificates
// in the store and get a handle to one of them.
//************************************************************
PCCERT_CONTEXT GetMySignerCert(HWND hwnd, HCERTSTORE hCertStore)
{
    PCCERT_CONTEXT         pPrevCertContext = NULL;
    PCCERT_CONTEXT         pCertContext = NULL;
    BOOL                   fReturnFlag = FALSE;
    BOOL                   fTestFlag;
    DWORD                  dwSize = NULL;
    CRYPT_KEY_PROV_INFO    *pKeyInfo = NULL;

    while(TRUE)
    {
        pCertContext = CertEnumCertificatesInStore(
                        hCertStore,
                        pPrevCertContext);
        if(!pCertContext)
        {
            fTestFlag = FALSE;
            break;
        }
        else
        {
            // For clarity, this code searches for the first
            // occurrence of a certificate containing an exchange key.
            // This works here, as there is only one pair of
            // certificates in the store. Normally you would search
            // for a name as well as the key type.

            // Call CertGetCertificateContextProperty to get the
            // struct size.

            fReturnFlag = CertGetCertificateContextProperty(
                                pCertContext,
                                CERT_KEY_PROV_INFO_PROP_ID,
                                NULL,
                                &dwSize);
            if(FALSE == fReturnFlag)
                MessageBox(hwnd, "Error Getting Key Property",
                                NULL, MB_OK);

            // Allocate memory for the returned structure.
            if(pKeyInfo)
                free(pKeyInfo);
            pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
            if(!pKeyInfo)
            {
                AfxMessageBox("Error Allocating Memory");
                fTestFlag = FALSE;
                break;
            }

            // Get the key info struct.
            fReturnFlag = CertGetCertificateContextProperty(
                                pCertContext,
                                CERT_KEY_PROV_INFO_PROP_ID,
                                pKeyInfo,
                                &dwSize);

            // Does it have a signature key?
            if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
            {
                fTestFlag = TRUE;
                break;
            }

        }
        pPrevCertContext = pCertContext;
    }
    if(pKeyInfo)
        free(pKeyInfo);

    if(FALSE == fTestFlag)
    {
        MessageBox(hwnd, "Signature Cert Not Found",
                        NULL, MB_OK);
        return NULL;
    }else
        return (pCertContext);
}


Using Simplified Message Functions

A group of high-level functions has been provided to simplify and shorten the amount of code necessary to accomplish the usual message manipulation tasks. This group of functions is called Simplified Message Functions, and all the functions contain the word "Message" somewhere in their name. A list of these functions and the details of them can be found in Simplified Message Functions.

As previously mentioned, these functions are at a higher level than the base cryptographic functions or the low-level message functions. They wrap several of the base cryptographic, low-level message, and certificate functions into a single function that performs a specific task in a specific manner, such as encrypting a PKCS #7 message or signing a message. These functions provide a quick way to get started using the Microsoft® CryptoAPI by reducing the number of function calls that you must use to accomplish a task.

There are two categories of tasks that are presented in this chapter:

  • Signing Data and Verifying Signed Data
    • Creating a signed message
    • Verifying a message signature
  • Encrypting and Decrypting Message Content
    • Creating an encrypted message
    • Decrypting a message


Signing Data and Verifying Signed Data

The simplified message functions make it easier to sign data and to verify signed data. The procedures for signing and verifying data, and example code demonstrating function usage, are in the sections that follow.


Creating a Signed Message

In this section, the generic steps to signing data are reviewed. The following illustration depicts the individual tasks that must be accomplished, as shown in the list that follows it.

To create a signed message
  1. Create the data (if necessary) and get a pointer to it.
  2. Open a certificate store that contains the signer's certificate.
  3. Get the private key from the certificate. There are two properties that must be set on the certificate before using it—one is used to tie a certificate to a particular CSP, and within that CSP, to a particular private key, and the other is used to indicate which hashing algorithm is to be used when a digest operation is called for. These need only be set once.
  4. From the certificate property, determine the hash algorithm.
  5. Send the data through the hashing function by using the hashing algorithm, thus creating a hash (digest) of the data.
  6. Using the private key obtained through the property on the certificate, encrypt the digest, creating the signature.
  7. Include the following in the signed message:
    • The signed data
    • The hash algorithm
    • The signature
    • The signer ID (certificate issuer and serial number)
    • The signer's certificate (optional)


Using the CryptSignMessage Function and Associated Structures

A single function, CryptSignMessage, is provided to accomplish all of the tasks listed in the previous section. However, initialization of structures and other data is necessary first. The following illustration shows the relationship between those function parameters that point to structures or arrays and their initialized data. The illustration shows only the function parameters and structure members that are derived from other structures or functions. The rest of the parameters are straightforward initializations.

To sign data by using CryptSignMessage
  1. Get a pointer to the data that is to be signed.
  2. Assign the pointer to the data to index zero of a "data to be signed" array.
  3. Get a handle to the cryptographic provider.
  4. Open a certificate store that contains the signer's certificate.
  5. Get an address to the signer's certificate.
  6. Assign the address of the certificate to index zero of the MsgCert array.
  7. Assign the addresses of any other certificates to be included with the message to the MsgCert array.
  8. Initialize the CRYPT_ALGORITHM_IDENTIFIER structure, initializing the pszObjId member to the desired hash algorithm, and the other members as appropriate.
  9. Initialize the CRYPT_SIGN_MESSAGE_PARA structure, initializing the pSigningCert member to the address of the signer's certificate and the MsgCert array member to the address of the signer's and other's certificates, the HashAlgorithm member to the address of the CRYPT_ALGORITHM_IDENTIFIER structure, and the other members as appropriate.
  10. Call the CryptSignMessage function, passing the CRYPT_SIGN_MESSAGE_PARA structure for the pSignPara parameter, the address of the "data to be signed" array for the rgpbToBeSigned parameter, an address for the pbSignedBlob output parameter, and values for the other parameters as appropriate.


Example Code Using CryptSignMessage

The following example code implements the procedure described in the previous section. Comments show which code fragments pertain to each step in the procedure. The details of the functions and structures can be found in Cryptographic Functions, Simplified Message Functions, and Data Structures.

//-------------------------------------------------------------
//-------------------------------------------------------------
// EXAMPLE CODE - SIGNING DATA FOR A MESSAGE USING
// CryptSignMessage().
//-------------------------------------------------------------
//-------------------------------------------------------------

//-------------------------------------------------------------
// Get a pointer to the message - this code creates a message
// and gets a pointer to it. In reality, usually the message
// will exist somewhere and a pointer will get passed to the
// application (Step 1).
//-------------------------------------------------------------
char szMessage[] = "Secret Message";    // The message
char* pszMessage = szMessage;           // A string pointer
BYTE* pbMessage = (BYTE*) pszMessage;   // A byte pointer
DWORD cbMessage = sizeof(szMessage);    // Size of message

AfxMessageBox(pszMessage);

//-------------------------------------------------------------
// Create the MessageArray (Step 2).
//-------------------------------------------------------------
const BYTE*    MessageArray[] = {pbMessage};
DWORD   MessageSizeArray[1];
MessageSizeArray[0] = cbMessage;

//-------------------------------------------------------------
// Get a handle to a crytographic provider (Step 3).
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
          &hCryptProv,           // Address for handle to be returned.
          NULL,                  // Use the current user's logon name.
          NULL,                  // Use the default provider.
          PROV_RSA_FULL,         // Need to do both encrypt & sign.
          NULL);                 // No flags needed.
if(TRUE != fReturn)
   ; // An error occurred. Call GetLastError and handle.
fReturn = FALSE;

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open a system certificate store (Step 4).
//-------------------------------------------------------------
HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the cert store handle now resides
// at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to your signature certificate (Step 5).
//-------------------------------------------------------------
PCCERT_CONTEXT    pSignerCert = NULL;

// Call the GetMySignerCert function. See the function code at the end
// of this code fragment.
pSignerCert = GetMySignerCert(hStoreHandle);
if(!pSignerCert)
{
    AfxMessageBox( "Error Getting Signer Cert");
    return;
}

//-------------------------------------------------------------
// Create a MsgCertArray (Step 6).
//-------------------------------------------------------------
PCCERT_CONTEXT MsgCertArray[1];
MsgCertArray[0] = pSignerCert;

//-------------------------------------------------------------
// Normally, at this point, additional certificates would be
// assigned to index locations within MsgCertArray. For the sake
// of clarity, this step is bypassed in this example, and only
// the signer's certificate is included with the message.
// (Step 7)
//-------------------------------------------------------------

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure (Step 8).
//-------------------------------------------------------------
DWORD                         HashAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    HashAlgorithm;
HashAlgSize = sizeof(HashAlgorithm);
memset(&HashAlgorithm, 0, HashAlgSize);     // Init. to zero.
HashAlgorithm.pszObjId = szOID_RSA_MD5;     // Then set the
                                            //   necessary field.

//-------------------------------------------------------------
// Initialize the signature structure (Step 9).
//-------------------------------------------------------------
CRYPT_SIGN_MESSAGE_PARA    SigParams;
DWORD SigParamsSize = sizeof(SigParams);
memset(&SigParams, 0, SigParamsSize);    // Init. to zero
                                         // Then set the necessary
                                         //   fields.
SigParams.cbSize = SigParamsSize;
SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
SigParams.pSigningCert = pSignerCert;
SigParams.HashAlgorithm = HashAlgorithm;
SigParams.cMsgCert = 1;
SigParams.rgpMsgCert = MsgCertArray;

//-------------------------------------------------------------
// Sign the message (Step 10).
//-------------------------------------------------------------

// Get the size of the output SignedBlob.
DWORD    cbSignedMessageBlob = NULL;

fReturn = FALSE;
fReturn = CryptSignMessage(
          &SigParams,            // Signature parameters
          FALSE,                 // Not detached
          1,                     // Number of messages
          MessageArray,          // Messages to be signed
          MessageSizeArray,      // Size of messages
          NULL,                  // Buffer for signed msg
          &cbSignedMessageBlob); // Size of buffer
if(FALSE == fReturn)
    AfxMessageBox("Getting Signed Blob Size Failed");

// Allocate memory for the signed blob.
BYTE*    pbSignedMessageBlob;
pbSignedMessageBlob = (BYTE*)malloc(cbSignedMessageBlob);
memset(pbSignedMessageBlob, 49, cbSignedMessageBlob);
if(!pbSignedMessageBlob)
    AfxMessageBox("Memory allocation error while signing");

// Get the SignedMessageBlob.
DWORD    dwLastError;
fReturn = FALSE;
fReturn = CryptSignMessage(
          &SigParams,            // Signature parameters
          FALSE,                 // Not detached
          1,                     // Number of messages
          MessageArray,          // Messages to be signed
          MessageSizeArray,      // Size of messages
          pbSignedMessageBlob,   // Buffer for signed msg
          &cbSignedMessageBlob); // Size of buffer
if(FALSE == fReturn)
{
    dwLastError = GetLastError();
    AfxMessageBox("Getting Signed Blob Failed");
}else
    AfxMessageBox("Meassge was signed successfully");

// If the call was successful, the signed blob now resides at
// the location pointed to by pbSignedMessageBlob.

... use the message.

//-------------------------------------------------------------
// Clean up, free memory, and so forth.
//-------------------------------------------------------------
free(pbSignedMessageBlob);
CertFreeCertificateContext(pSignerCert);
fReturn = CertCloseStore(
          hStoreHandle,
          CERT_CLOSE_STORE_CHECK_FLAG);
if(FALSE == fReturn)
    AfxMessageBox("Store Closed After Signing - \n"
          "Not All Certs or CRLs Were Freed");

//*****************************************************************
// GetMySignerCert() - A function to enumerate all the certificates
// in the store and get a handle to one of them.
//*****************************************************************
PCCERT_CONTEXT GetMySignerCert(HCERTSTORE hCertStore)
{
    PCCERT_CONTEXT       pPrevCertContext = NULL;
    PCCERT_CONTEXT       pCertContext = NULL;
    BOOL                 fReturnFlag = FALSE;
    BOOL                 fTestFlag;
    DWORD                dwSize = NULL;
    CRYPT_KEY_PROV_INFO* pKeyInfo = NULL;

    while(TRUE)
    {
        pCertContext = CertEnumCertificatesInStore(
                       hCertStore,
                       pPrevCertContext);
        if(!pCertContext)
        {
             fTestFlag = FALSE;
             break;
        }
        else
        {
            // For clarity, this code searches for the first
            // occurrence of a signature key. This works here,
            // as there is only one certificate in the store. Normally
            // you would search for a name as well as the key type.

            // Call CertGetCertificateContextProperty to get the
            // returned structure size.
            fReturnFlag = CertGetCertificateContextProperty(
                      pCertContext,
                      CERT_KEY_PROV_INFO_PROP_ID,
                      NULL,
                      &dwSize);
            if(FALSE == fReturnFlag)
                AfxMessageBox("Error Getting Key Property");

            // Allocate memory for the returned structure.
            If(pKeyInfo)
                free(pKeyInfo);
            pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
            if(!pKeyInfo)
                AfxMessageBox("Error Allocating Memory");

            // Get the key info structure.
            fReturnFlag = CertGetCertificateContextProperty(
                          pCertContext,
                          CERT_KEY_PROV_INFO_PROP_ID,
                          pKeyInfo,
                          &dwSize);

            // Does it have a signature key?
            if(pKeyInfo->dwKeySpec == AT_SIGNATURE)
            {
                AfxMessageBox("Signaure Cert Found");
                fTestFlag = TRUE;
                break;
            }

        }
        pPrevCertContext = pCertContext;
    }
    CertFreeCertificateContext(pPrevCertContext);
    if(pKeyInfo)
        free(pKeyInfo);

    if(FALSE == fTestFlag)
    {
        AfxMessageBox("Signature Cert Not Found");
        return NULL;
    }else
        return (pCertContext);
}


Verifying A Signed Message

The steps to verifying the signature of signed data are reviewed here. The following illustration depicts the individual tasks that must be accomplished, as shown in the list that follows it.

To verify the signature of a signed message
  1. Get a pointer to the signed message.
  2. Open a certificate store.
  3. Using the signer ID contained in the message, get the sender's certificate and get a handle to it's public key.
  4. Alternate to # 2 and #3: Use the certificate contained in the message to retrieve the signer's public key.
  5. Using the signer's public key, decrypt the digital signature, producing the original digest of the data in the message.
  6. Using the hash algorithm contained in the message, hash the data contained in the message, yielding a new digest.
  7. Compare the digest retrieved from the message with the new digest just created.
  8. If the two digests match, the signature is verified. This means that the private key that was used to sign the data matches the public key just used to decrypt the signature, and that the data has not changed since the data was signed.

    If the two digests do not match, the signature is not verified, and either the private/public keys do not match, or the data has been changed since the data was signed, or both.


Using the CryptVerifyMessageSignature Function

A single function, CryptVerifyMessageSignature, can be used to verify a signature, as shown in the following procedure.

To verify a signed message
  1. Get a pointer to the signed message.
  2. Get the size of the signed message.
  3. Get a handle on a cryptographic provider.
  4. Initialize the CRYPT_VERIFY_MESSAGE_PARA structure.
  5. Call CryptVerifyMessageSignature to verify the signature.


Example Code Using CryptVerifyMessageSignature

The following example code implements the procedure described in the previous section. Comments show which code fragments pertain to each step in the procedure. The details of the functions and structures can be found in Simplified Message Functions and Data Structures.

//-------------------------------------------------------------
//-------------------------------------------------------------
// EXAMPLE CODE TO VERIFY THE SIGNED MESSAGE JUST CREATED, BY
// USING THE CryptVerifyMessageSignature FUNCTION.
//-------------------------------------------------------------
//-------------------------------------------------------------

//-------------------------------------------------------------
// Get a pointer to and the size of the signed data. The pointer
// to the signed data blob, pbSignedMessageBlob, and the size,
// cbSignedMessageBlob, created in the previous code are used
// (Steps 1 and 2).
//-------------------------------------------------------------

//-------------------------------------------------------------
// Get a handle to a cryptographic provider. The handle,
// hCryptProv, created in the previous code is used (Step 3).
//-------------------------------------------------------------

//-------------------------------------------------------------
// Initialize the CRYPT_VERIFY_MESSAGE_PARA structure (Step 4).
// Also, see the GetSignerCertificate() function at the end of
// this code fragment.
//-------------------------------------------------------------
char    VerifyArgs[] = "Arguments";
CRYPT_VERIFY_MESSAGE_PARA        VerifyParams;
DWORD VerifyParamsSize = sizeof(VerifyParams);
memset(&VerifyParams, 0, VerifyParamsSize);  // Initialize to zero.
                                             // Then set the
                                             //  necessary fields.
VerifyParams.cbSize = VerifyParamsSize;
VerifyParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
VerifyParams.hCryptProv = hCryptProv;
VerifyParams.pfnGetSignerCertificate = GetSignerCertificate;
VerifyParams.pvGetArg = VerifyArgs;

//-------------------------------------------------------------
// Call CryptVerifyMessageSignature    (Step 5).
//-------------------------------------------------------------
fReturn = CryptVerifyMessageSignature(
            &VerifyParams,            // Verify parameters
            0,                        // Signer index
            pbSignedMessageBlob,      // Pointer to signed blob
            cbSignedMessageBlob,      // Size of signed blob
            NULL,                     // Buffer for decoded msg
            NULL,                     // Size of buffer
            NULL);                    // Pointer to signer cert
if(FALSE == fReturn)
    AfxMessageBox("Could Not Verify Message Signature");
else
    AfxMessageBox("Signature Verified");

//-------------------------------------------------------------
// Clean up, free memory, and so forth.
//-------------------------------------------------------------
free(pbSignedMessageBlob);

//************************************************************
// GetSignerCertificate() - A callback function to get a certificate
// from a store.
//************************************************************
static PCCERT_CONTEXT WINAPI GetSignerCertificate(
IN void *pvVerifyArg,
IN DWORD dwCertEncodingType,
IN PCERT_INFO pSignerId,    // Only the Issuer and SerialNumber
                            // fields are used
IN HCERTSTORE hMsgCertStore)
{

return CertGetSubjectCertificateFromStore(    hMsgCertStore,
                                            dwCertEncodingType,
                                            pSignerId);
}


Encrypting and Decrypting Message Content

The simplified message functions make it easier to encrypt and decrypt data. The procedures for encrypting and decrypting data, and example code demonstrating function usage are in the sections that follow.


Creating an Encrypted Message

The following illustration depicts the individual tasks that must be accomplished to encrypt a message, as shown in the list that follows it.

To encrypt a message
  1. Get a pointer to the plaintext message.
  2. Generate a symmetric (session) key.
  3. Using the symmetric key and specified encryption algorithm, encrypt the message data.
  4. Open a certificate store.
  5. Get the recipient's certificate.
  6. Get the public key from the recipient's certificate .
  7. Using the recipient's public key, encrypt the symmetric key.
  8. Get the recipient's ID from the recipient's certificate .
  9. Include the following in the digitally enveloped message: the data encryption algorithm, the encrypted data, the encrypted symmetric key, and the recipient ID.


Using the CryptEncryptMessage Function and Associated Structures

CryptEncryptMessage, is the only function call necessary to accomplish all of the tasks listed in the previous section. Here again, initialization of structures and other data is necessary first. The following illustration shows the relationship between those function parameters that point to structures or arrays and their initialized data.

To encrypt data
  1. Get a pointer to the content to be encrypted.
  2. Get the size of the content to be encrypted.
  3. Get a handle on a cryptographic provider.
  4. Open a certificate store.
  5. Get the recipient certificate.
  6. Create the "recipient cert" array.
  7. Initialize the CRYPT_ALGORITHM_IDENTIFIER structure.
  8. Initialize the CRYPT_ENCRYPT_MESSAGE_PARA structure.
  9. Call CryptEncryptMessage to encrypt the content and create a digitally enveloped message.


Example Code Using CryptEncryptMessage

The following example code implements the procedure just presented. Comments show which code fragments pertain to each step in the procedure. The details of the functions and structures can be found in Simplified Message Functions and Data Structures.

//-------------------------------------------------------------
//-------------------------------------------------------------
// EXAMPLE CODE FOR ENCRYPTING DATA AND CREATING AN ENVELOPED
// MESSAGE USING CryptEncryptMessage().
//-------------------------------------------------------------
//-------------------------------------------------------------

// Use this constant definition (or one similar to it) to define
// a single encoding type that can be used in all parameters and
// data members that require one or the other or both.
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

//-------------------------------------------------------------
// Get a pointer to the message - this code creates a message
// and gets a pointer to it. In reality, the content
// will usually exist somewhere and a pointer will get passed to the
// application (Steps 1 and 2).
//-------------------------------------------------------------
char szContent[] = "A Razzle-Dazzle\n"
                        "Secret Message";    // The message
char* pszContent = szContent;                // A string pointer
BYTE* pbContent = (BYTE*) pszContent;        // A byte pointer
DWORD cbContent = sizeof(szContent);         // Size of message

AfxMessageBox(pszContent);

//-------------------------------------------------------------
// Get a handle to a cryptographic provider (Step 3).
//-------------------------------------------------------------
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
            &hCryptProv,         // Address for handle to be returned.
            NULL,                // Use the current user's logon name.
            NULL,                // Use the default provider.
            PROV_RSA_FULL,       // Need to do both encrypt & sign.
            NULL);               // No flags needed.
if(TRUE != fReturn)
    ; // An error occurred. Call GetLastError and handle.
fReturn = FALSE;

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

//-------------------------------------------------------------
// Open the system certificate store (Step 4).
//-------------------------------------------------------------

HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the certificate store handle now
// resides at the location pointed to by hStoreHandle.

//-------------------------------------------------------------
// Get a pointer to the recipients certificate (Step 5).
//-------------------------------------------------------------
PCCERT_CONTEXT    pRecipientCert = NULL;

// Call GetRecipientCert. See the function code at the end of
// this code fragment.
pRecipientCert = GetRecipientCert(hStoreHandle);
if(!pRecipientCert)
{
    AfxMessageBox( "Error Getting Recipient Cert");
    return;
}
//-------------------------------------------------------------
// Create a RecipientCertArray (Step 6).
//-------------------------------------------------------------
PCCERT_CONTEXT RecipientCertArray[1];
RecipientCertArray[0] = pRecipientCert;

//-------------------------------------------------------------
// Initialize the Algorithm Identifier structure. (Step 7).
//-------------------------------------------------------------
DWORD                        EncryptAlgSize;
CRYPT_ALGORITHM_IDENTIFIER    EncryptAlgorithm;
EncryptAlgSize = sizeof(EncryptAlgorithm);
// Initialize the structure to zero.
memset(&EncryptAlgorithm, 0, EncryptAlgSize);
// Set the necessary field.
EncryptAlgorithm.pszObjId = szOID_RSA_RC4;

//-------------------------------------------------------------
// Initialize the CRYPT_ENCRYPT_MESSAGE_PARA structure. (Step 8).
//-------------------------------------------------------------
CRYPT_ENCRYPT_MESSAGE_PARA    EncryptParams;
DWORD    EncryptParamsSize = sizeof(EncryptParams);
memset(&EncryptParams, 0, EncryptParamsSize);

EncryptParams.cbSize =  EncryptParamsSize;
// For details on MY_ENCODING_TYPE, see the constant
// definition at the beginning of this code fragment.
EncryptParams.dwMsgEncodingType = MY_ENCODING_TYPE;
EncryptParams.hCryptProv = hCryptProv;
EncryptParams.ContentEncryptionAlgorithm = EncryptAlgorithm;

//-------------------------------------------------------------
// Call CryptEncryptMessage() (Step 9).
//-------------------------------------------------------------
//BYTE*    pbEncryptedBlob;
//DWORD    cbEncryptedBlob;

fReturn = CryptEncryptMessage(
          &EncryptParams,
          1,
          RecipientCertArray,
          pbContent,
          cbContent,
          NULL,
          &cbEncryptedBlob);
if(TRUE != fReturn)
{
    AfxMessageBox( "Getting EncrypBlob Size Failed");
    return;
}

// Allocate memory for the returned blob.
pbEncryptedBlob = (BYTE*)malloc(cbEncryptedBlob);
if(!pbEncryptedBlob)
    AfxMessageBox("Memory Allocation Error While Encrypting");

// Call CryptEncryptMessage again to encrypt the content.
fReturn = CryptEncryptMessage(
          &EncryptParams,
          1,
          RecipientCertArray,
          pbContent,
          cbContent,
          pbEncryptedBlob,
          &cbEncryptedBlob);

if(TRUE == fReturn)
    AfxMessageBox( "Encryption Succeeded");
else
    AfxMessageBox( "Encryption Failed");

// If the function call succeeded, the encrypted blob now resides
// at the location pointed to by pbEncryptedBlob.

//-------------------------------------------------------------
// Clean up memory.
//-------------------------------------------------------------
CertFreeCertificateContext(pRecipientCert);
fReturn = CertCloseStore(
          hStoreHandle,
          CERT_CLOSE_STORE_CHECK_FLAG);
if(FALSE == fReturn)
    AfxMessageBox("Store Closed After Encryption - \n"
                  "Not All Certs or CRLs Were Freed");

//************************************************************
// GetRecipientCert() - A function to enumerate all the certificates
// in the store and get a handle to one of them.
//************************************************************
PCCERT_CONTEXT GetRecipientCert(HCERTSTORE hCertStore)
{
    PCCERT_CONTEXT       pPrevCertContext = NULL;
    PCCERT_CONTEXT       pCertContext = NULL;
    BOOL                 fReturnFlag = FALSE;
    BOOL                 fTestFlag;
    DWORD                dwSize = NULL;
    CRYPT_KEY_PROV_INFO* pKeyInfo = NULL;

    while(TRUE)
    {
        pCertContext = CertEnumCertificatesInStore(
                       hCertStore,
                       pPrevCertContext);
        if(!pCertContext)
        {
            fTestFlag = FALSE;
            break;
        }
        else
        {
            // For clarity, this code searches for the first
            // occurrence of a signature key. This works here,
            // as there is only one certificate in the store. Normally
            // you would search for a name as well as the key type.

            // Call CertGetCertificateContextProperty to get the
            // returned structure size.
            fReturnFlag = CertGetCertificateContextProperty(
                          pCertContext,
                          CERT_KEY_PROV_INFO_PROP_ID,
                          NULL,
                          &dwSize);
            if(FALSE == fReturnFlag)
                AfxMessageBox("Error Getting Key Property");

            // Allocate memory for the returned structure.
            If(pKeyInfo)
                free(pKeyInfo);
            pKeyInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
            if(!pKeyInfo)
                AfxMessageBox("Error Allocating Memory");

            // Get the key information structure.
            fReturnFlag = CertGetCertificateContextProperty(
                          pCertContext,
                          CERT_KEY_PROV_INFO_PROP_ID,
                          pKeyInfo,
                          &dwSize);

            // Does it contain an exchange key?
            if(pKeyInfo->dwKeySpec == AT_KEYEXCHANGE)
            {
                AfxMessageBox("KeyExchange Cert Found");
                fTestFlag = TRUE;
                break;
            }

        }
        pPrevCertContext = pCertContext;
    }
    CertFreeCertificateContext(pPrevCertContext);
    if(pKeyInfo)
    free(pKeyInfo);

    if(FALSE == fTestFlag)
    {
        AfxMessageBox("KeyExchange Cert Not Found");
        return NULL;
    }else
        return (pCertContext);
}


Decrypting an Encrypted Message

In this section, the steps to decrypt an encrypted message are presented. The following illustration depicts the individual tasks that must be accomplished, as shown in the list that follows it.

To decrypt an encrypted message
  1. Get a pointer to the digitally enveloped message.
  2. Open a certificate store.
  3. From the message, retrieve the recipient ID (My ID).
  4. Use the recipient ID to retrieve the certificate.
  5. Get the private key from the certificate.
  6. Use the private key to decrypt the symmetric (session) key.
  7. Retrieve the encryption algorithm from the message.
  8. Using the private key and encryption algorithm, decrypt the data.


Using the CryptDecryptMessage Function and Associated Structures

Only CryptDecryptMessage is needed to accomplish all of the tasks listed in the previous section. Initialization of structures and other data is necessary first. The following illustration shows the relationship between those function parameters that point to structures or arrays and their initialized data.

To decrypt data using CryptDecryptMessage
  1. Get a pointer to the encrypted blob.
  2. Get a pointer to a certificate store.
  3. Create a certificate store array.
  4. Initialize the CRYPT_DECRYPT_MESSAGE_PARA structure.
  5. Call CryptDecryptMessage to decrypt the data contained in the message.


Example Code Using CryptDecryptMessage

The following example code implements the procedure just presented. Comments show which code fragments pertain to each step in the procedure. The details of the functions and structures can be found in Simplified Message Functions and Data Structures.

//-------------------------------------------------------------
//-------------------------------------------------------------
// EXAMPLE CODE FOR DECRYPTING AN ENCRYPTED MESSAGE USING
// CryptDecryptMessage().
//-------------------------------------------------------------
//-------------------------------------------------------------

//-------------------------------------------------------------
// Get a pointer to the encrypted message. Use the pointers,
// pbEncryptedBlob and cbEncryptedBlob, retrieved in the
// previous code segment (Step 1).
//-------------------------------------------------------------

// View the encrypted blob.

char*    EncryptedString = new char[(cbEncryptedBlob *2) +1];

// Call a routine to convert the byte blob to ASCII HEX. See the
// function code at the end of this code fragment.
BytesToStr(cbEncryptedBlob, pbEncryptedBlob, EncryptedString);

// Show the string.
AfxMessageBox(EncryptedString);

//-------------------------------------------------------------
// Open the system certificate store (Step 2).
//-------------------------------------------------------------
//HCERTSTORE        hStoreHandle = NULL;

// Call CertOpenSystemStore to open the store.
hStoreHandle = CertOpenSystemStore(hCryptProv, "MY");
if (!hStoreHandle)
{
    AfxMessageBox( "Error Getting Store Handle");
    return;
}

// If the call was successful, the certificate store handle now
// resides at the location pointed to by hStoreHandle.

// Create a "CertStoreArray" (Step 3)
HCERTSTORE        CertStoreArray[] = {hStoreHandle};

//-------------------------------------------------------------
// Initialize the CRYPT_DECRYPT_MESSAGE_PARA structure. (Step 4).
//-------------------------------------------------------------
CRYPT_DECRYPT_MESSAGE_PARA        DecryptParams;
DWORD    DecryptParamsSize = sizeof(DecryptParams);
memset(&DecryptParams, 0, DecryptParamsSize);

DecryptParams.cbSize = DecryptParamsSize;
DecryptParams.dwMsgAndCertEncodingType = MY_ENCODING_TYPE;
DecryptParams.cCertStore = 1;
DecryptParams.rghCertStore = CertStoreArray;

//-------------------------------------------------------------
// Decrypt the message data (Step 5).
//-------------------------------------------------------------
DWORD        cbDecryptedMessage;

// Call CryptDecryptMessage to get the returned data size.
fReturn = CryptDecryptMessage(
          &DecryptParams,
          pbEncryptedBlob,
          cbEncryptedBlob,
          NULL,
          &cbDecryptedMessage,
          NULL);
if(FALSE == fReturn)
    AfxMessageBox( "Error Getting Decrypted Message Size");

// Allocate memory for the returned decrypted data.
BYTE*    pbDecryptedMessage;

pbDecryptedMessage = (BYTE*)malloc(cbDecryptedMessage);
if(!pbDecryptedMessage)
    AfxMessageBox("Memory Allocation Error While Decrypting");

// Call CryptDecryptMessage to decrypt the data.
fReturn = CryptDecryptMessage(
          &DecryptParams,
          pbEncryptedBlob,
          cbEncryptedBlob,
          pbDecryptedMessage,
          &cbDecryptedMessage,
          NULL);
LPSTR    DecryptedString = (LPSTR) pbDecryptedMessage;

if(FALSE == fReturn)
    AfxMessageBox("Error Decrypting The Data");
else
{
    AfxMessageBox("Data Decrypted Successfully");
    AfxMessageBox(DecryptedString);    // Display the string.
}

// If the function call succeeded, the decrypted message now
// resides at the location pointed to by pbDecryptedMessage.

//-------------------------------------------------------------
// Clean up memory.
//-------------------------------------------------------------

fReturn = CertCloseStore(
          hStoreHandle,
          CERT_CLOSE_STORE_CHECK_FLAG);
if(FALSE == fReturn)
    AfxMessageBox("Store Closed After Decryption - \n"
                  "Not All Certs or CRLs Were Freed");

free(pbEncryptedBlob);
free(pbDecryptedMessage);
delete [] EncryptedString;

//************************************************************
// BytesToStr() - Converts the bytes into CHAR hex. Needs
// (cb * 2 + 1) * sizeof(CHAR) bytes of space in sz.
//************************************************************
static void BytesToStr(DWORD cb, void* pv, LPSTR sz)
{

    BYTE* pb = (BYTE*) pv;
    for (DWORD i = 0; i<cb; i++)
    {
        int b;

        b = (*pb & 0xF0) >> 4;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';
        b = *pb & 0x0F;
        *sz++ = (b <= 9) ? b + '0' : (b - 10) + 'A';

        pb++;
    }
    *sz++ = 0;
}


Reference Overview

This reference contains detail information about all of the Microsoft® CryptoAPI functions, data types, and structures. This information is divided into the following sections:

  • Certificate Store Functions
  • Certificate Helper Functions
  • CryptEncodeObject/CryptDecodeObject Functions
  • Cryptographic Functions
  • Simplified Message Functions
  • Data Types and Constants
  • Data Structures


Certificate and Message Encoding Types

Many of the functions specify the certificate and/or message encoding types. This encoding type is a DWORD, possibly containing both the certificate and message encoding types. The certificate encoding type is stored in the low-order word. The message encoding type is stored in the high order word. Some functions or structure fields require only one of the encoding types, but it is always acceptable to specify both encoding types. See the beginning of Signed Message Example Code for an example that specifies both encoding types.

The following naming convention is used to indicate which encoding type(s) are required:

Name | comments
dwMsgAndCertEncodingType | Both encoding types are required.
dwMsgEncodingType | Only the message encoding type is required.
dwCertEncodingType | Only the certificate encoding type is required.
dwEncodingType | Either a message or certificate encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:

Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000


Common In/Out Parameter Conventions

Many of the functions return a potentially large amount of data to an address provided in one of the parameters by the application program. In all these cases, the operation is performed in a similar, if not identical, fashion. The parameter that points to the location of the returned data will have the notation convention where "pb" is the first two characters of the parameter name. Another parameter will have "pcb" as the first three characters of the parameter name. This parameter represents the size, in bytes, of the data that will be returned to the "pb" location. For example, consider the following function specification:

BOOL WINAPI SomeFunction(
  PCCRL_CONTEXT pCrlContext,  // in
  DWORD dwPropId,             // in
  BYTE *pbData,               // out
  DWORD *pcbData              // in/out
);

In this example pbData is the location where the data will be returned, and pcbData is the size, in bytes, of the returned data.

Note The companion parameter to the "pcb" parameter may sometimes carry a slightly different prefix, such as "p" or "pv".

Also, for companion parameters using the combination of prefixes:"pwsz" and "pcch", the "pcch" parameter is the count in characters (UNICODE or ASCII, as applicable), of the returned data.

If the buffer specified by pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code (which can be seen by calling GetLastError), and stores the required buffer size, in bytes, into the variable pointed to by pcbData.

If pbData is NULL, and pcbData is non-NULL, then no error is returned and the function returns the size of the needed memory buffer, in bytes, in the variable pointed to by pcbData. This lets an application determine the size of, and the best way to allocate, a buffer for the returned data.

Note When pbData = NULL is used to determine the size needed to insure that the returned data fits in the specified buffer, it should be noted that the second call to the function (which populates the buffer with the desired data) may not use the whole buffer. After the second call, the actual size of the data returned is contained in pcbData, and it is this size that should be used when processing the data.

See Efficient Use of Common In/Out Parameter Conventions for information on optimizing performance when using this convention.

The following example code demonstrates how this operation might be implemented:

// Assume that the application has already declared and initialized all
// the necessary variables.

// Call SomeFunction() to get the size of the returned data.
BOOL        fReturn =            FALSE;

fReturn = SomeFunction(pCrlContext, dwPropId, NULL, &cbData);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the call succeeded, the size of the data, in bytes,
// now resides in cbData.

// Malloc memory for the size of the message.
BYTE* pbData;

pbData = (BYTE*)malloc(cbData);
if(pbData = NULL)
    ;// Handle the memory allocation error.

// Call SomeFunction() to return the data.

fReturn = SomeFunction(pCrlContext, dwPropId, pbData, &cbData);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the function succeeded, the data is now at the location pointed
// to by pbData. Note that cbData is updated with the actual size of
// the data returned, and it is this size that should be used when
// processing the data.


Efficient Use of Common In/Out Parameter Conventions

When using the Common In/Out Parameter Conventions for a given function, a performance gain might be realized by pre-allocating a buffer for the returned "pb" data, without querying that function for the exact size "cb" needed, dependent upon the specified data being input. Whenever a pre-allocated buffer is at least as big as the "cb" required by that function, a throughput savings is realized since the function is only called once, producing the returned data placed in the "pb" specified buffer.

The following example code demonstrates how a pre-allocated buffer can be used to provide a performance gain:

// Suppose that we have the same SomeFunction from the example in
// the Common In/Out Parameter Conventions, that it is called
// very repetitively by an application, and that we know that a
// buffer size of 50 bytes will handle the output for all but a
// few cases for the input data.

// Setup SomeFunction variables
PCCRL_CONTEXT pCrlContext; // Initialized elsewhere.
DWORD dwPropId;            // Initialized elsewhere.

// We can write code to pre-allocate a 50 byte buffer, and
// use that buffer in a call to SomeFunction which should produce the
// desired output data most of the time. However, we need to be
// prepared for a case where more than 50 bytes was required for the
// output data. For that case, we use the cb returned by the failed
// call to SomeFunction to allocate a bigger buffer. A provisional
// second call to SomeFunction using the larger buffer is then made.

DWORD cb = 50;
PBYTE pb; // pointer to byte buffer

if (NULL == (pb = (PBYTE)malloc(cb))) // attempt to allocate cb bytes
   goto Log_Memory_Allocation_Error;
// Memory successfully allocated, continue.
if (!SomeFunction(pCrlContext, dwPropId, pb, &cb))
   // A failure occurred. Determine if the buffer was too small.
   if (GetLastError() != ERROR_MORE_DATA)
      goto Log_SomeFunction_Failure;
   // Getting here means that the buffer wasn't big enough and that cb
   // has been updated with the size of the buffer required.
   if (NULL == (pb = (PBYTE)malloc(cb))) //attempt to allocate cb bytes
      goto Log_Memory_Allocation_Error;
   // Memory successfully allocated, continue.
   if (!SomeFunction(pCrlContext, dwPropId, pb, &cb))
      goto Log_SomeFunction_Failure;

// Getting here indicates a successful call to SomeFunction.
// pb points to the output data, cb contains the size of that data.

; // Process the data. Note that cb is updated with the actual size of
  // the data returned, and it is this size that should be used when
  // processing the data.

free(pb); // deallocate the buffer when done processing the data

return; // if appropriate

Log_SomeFunction_Failure :
   ; // Handle as desired
   return; // if appropriate
Log_Memory_Allocation_Error:
   ; // Handle as desired

The above example code can be rewritten into loop form, where the call to SomeFunction appears only once which reduces the amount of code generated when compiled. This is shown below:

BYTE cTryAgain = 2; // Used to make sure there is only one retry
                    // if the pre-allocated buffer was not big enough.

while (cTryAgain-- ){ // We break out for success.
   if (NULL == (pb = (PBYTE)malloc(cb)))
      goto Log_Memory_Allocation_Error;
   if (SomeFunction(pCrlContext, dwPropId, pb, &cb))
      break; // Success !
   free(pb); // If break not taken, function failure occurred.
             // Free the buffer on failure.
   // Check to see if the buffer was not big enough.
   if (GetLastError() != ERROR_MORE_DATA)
      // Some other failure occurred. Exit loop and log it.
      goto Log_SomeFunction_Failure;

   // In the case of ERROR_MORE_DATA, we stay in the loop, and
   // cb has been updated with the size of the buffer required.

}  // ends loop

// If loop exited because of success, process the output data.

; // Process the data. Note that cb is updated with the actual size of
  // the data returned, and it is this size that should be used when
  // processing the data.

free(pb); // Free the data buffer after the data has been processed.

   return; // if appropriate

Log_SomeFunction_Failure :
   ; // Handle as desired
   return; // if appropriate
Log_Memory_Allocation_Error:
   ; // Handle as desired

Another method of obtaining performance gains is to use alloca to allocate memory from the stack, instead of using malloc to allocate memory from the heap. Since the buffer is on the stack, free does not need to be called when finished using the buffer. When using alloca, it should be noted that the data buffer must be used locally to the calling function since upon function return, the buffer is automatically deallocated by the stack pop. Also, be aware that each call to alloca from the same function uses more stack. Excessive use may cause a stack overflow in very repetitive cases.


Cryptographic Functions

These low-level Win32® cryptographic functions were formerly in Microsoft® CryptoAPI version 1.0, and provide you the most flexibility in applying cryptography to your applications. These functions facilitate communication with the cryptographic service providers (CSP).

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CryptAcquireContext | Acquires a handle to a particular key container within a particular CSP.
CryptContextAddRef | Adds one to the reference count on a HCRYPTPROV handle.
CryptCreateHash | Initiates the hashing of a stream of data.
CryptDecrypt | Decrypts data that was previously encrypted via the CryptEncrypt function.
CryptDeriveKey | Generates cryptographic keys derived from base data.
CryptDestroyHash | Destroys the hash object referenced by the hHash parameter.
CryptDestroyKey | Releases the handle referenced by the hKey parameter. After a key handle has been released, it becomes invalid and cannot be used again.
CryptDuplicateHash | Makes an exact copy of a hash and the state the hash is in.
CryptDuplicateKey | Makes an exact copy of a key and the state the key is in.
CryptEncrypt | Encrypts data.
CryptEnumProviders | Enumerates the providers on a computer.
CryptEnumProviderTypes | Enumerates the types of providers supported on the computer.
CryptExportKey | Exports cryptographic keys out of a cryptographic service provider in a secure manner.
CryptFormatObject | Formats the encoded data and returns a Unicode string in the allocated buffer according to the certificate encoding type.
CryptGenKey | Generates random cryptographic keys for use with the CSP module.
CryptGenRandom | Fills a buffer with random bytes.
CryptGetDefaultProvider | Determines the default CSP either for the current user or the computer for a given provider type.
CryptGetHashParam | Retrieves data that governs the operations of a hash object.
CryptGetKeyParam | Retrieves data that governs the operations of a key.
CryptGetProvParam | Retrieves parameters that govern the operations of a CSP.
CryptGetUserKey | Retrieves a handle to a permanent user key pair, such as the user's signature key pair.
CryptHashData | Computes the cryptographic hash on a stream of data.
CryptHashSessionKey | Computes the cryptographic hash on a key object.
CryptImportKey | Transfers a cryptographic key from a key blob to a CSP.
CryptProtectData | Performs encryption on the data in a DATA_BLOB.
CryptQueryObject | Takes a CERT_BLOB or a file name and returns the information about the content of the blob or the file.
CryptReleaseContext | Releases a handle to a CSP and a key container.
CryptSetHashParam | In theory, this function customizes the operations of a hash object. Currently, only a single parameter is defined for this function.
CryptSetKeyParam | Customizes various aspects of a key's operations.
CryptSetProvider | Specifies the current user default CSP.
CryptSetProviderEx | Specifies either the current user default CSP or the computer default CSP.
CryptSetProvParam | Customizes the operations of a CSP.
CryptSignHash | Signs a piece of data.
CryptUnprotectData | Performs a decryption and integrity check of the data in a DATA_BLOB.
CryptVerifySignature | Verifies a signature against a hash object.


CryptAcquireContext

The CryptAcquireContext function is used to acquire a handle to a particular key container within a particular CSP. This returned handle can then be used to make calls to the selected CSP.

This function performs two operations. It first attempts to find a CSP with the characteristics described in the dwProvType and pszProvider parameters. If the CSP is found, then the function attempts to find a key container within the CSP matching the name specified by the pszContainer parameter.

This function can also be used to create and destroy key containers, depending on the value of the dwFlags parameter.

#include <wincrypt.h>
BOOL WINAPI CryptAcquireContext(
  HCRYPTPROV *phProv,   // out
  LPCTSTR pszContainer, // in
  LPCTSTR pszProvider,  // in
  DWORD dwProvType,     // in
  DWORD dwFlags         // in
);

Parameters

phProv
Address to which the function copies a handle to the CSP.
pszContainer
Key container name. This is a zero-terminated string that identifies the key container to the CSP. This name is independent of the method used to store the keys. Some CSPs will store their key containers internally (in hardware), some will use the system registry, and others will use the file system. pszContainer is to be set to NULL when dwFlags is set to CRYPT_VERIFYCONTEXT.

If this parameter is NULL, then a default key container name will be used. For example, if the Microsoft Base Cryptographic Provider is being used, then the current user's logon name will be used as the name of the key container. Other CSPs may also have default key containers that can be acquired in this way.

An application can obtain the name of the acquired key container at a later time by reading the PP_CONTAINER CSP parameter with the CryptGetProvParam function.

pszProvider
Provider name. This is a zero-terminated string that specifies the CSP to be used.

If this parameter is NULL then the user default provider is used. For more details, see Connecting to a Cryptographic Service Provider.

An application can obtain the name of the acquired CSP at a later time by reading the PP_NAME CSP parameter with the CryptGetProvParam function.

dwProvType
Type of provider to acquire. The following provider types are predefined, and are discussed in detail in Interfacing with a Cryptographic Service Provider (CSP).
  • PROV_RSA_FULL
  • PROV_RSA_SIG
  • PROV_DSS
  • PROV_DSS_DH
  • PROV_DH_SCHANNEL
  • PROV_FORTEZZA
  • PROV_MS_EXCHANGE
  • PROV_RSA_SCHANNEL
  • PROV_SSL
dwFlags
Flag values. This parameter is normally set to zero, but some applications will set one or more of the following flags:
  • CRYPT_VERIFYCONTEXT. If this flag is set, then the application will have no access to the private keys and the pszContainer parameter must be set to NULL.

    This option is intended to be used with applications that will not be using private keys.

    When CryptAcquireContext is called, many CSPs will require input from the owning user before granting access to the private keys in the key container. For example, the private keys may be encrypted, requiring a password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed.

  • CRYPT_NEWKEYSET. If this flag is set, then a new key container will be created with the name specified by pszContainer. If pszContainer is NULL, then a key container with the default name will be created. See CRYPT_MACHINE_KEYSET for information on combining flags.
  • CRYPT_MACHINE_KEYSET. By default, keys are stored in the HKEY_CURRENT_USER portion of the registry. The CRYPT_MACHINE_KEYSET flag can be combined with all of the other flags, indicating that the location for the key of interest is HKEY_LOCAL_MACHINE. When combined with the CRYPT_NEWKEYSET flag, the CRYPT_MACHINE_KEYSET flag is useful when access is being performed from a service or user account that did not log on interactively. This combination enables access to user specific keys under HKEY_LOCAL_MACHINE.

Note When key containers are created, most CSPs will not automatically create any public/private key pairs. These keys must be created as a separate step with the CryptGenKey function.

  • CRYPT_DELETEKEYSET. If this flag is set, then the key container specified by pszContainer is deleted. If pszContainer is NULL, then the key container with the default name is deleted. All key pairs in the key container are also destroyed.

    When the CRYPT_DELETEKEYSET flag is set, the value returned in phProv is undefined and, thus, the CryptReleaseContext function need not be called afterwards.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory during the operation.
NTE_BAD_FLAGS | The dwFlags parameter has an illegal value.
NTE_BAD_KEYSET | The registry entry for the key container could not be opened and may not exist.
NTE_BAD_KEYSET_PARAM | The pszContainer or pszProvider parameter is set to an illegal value.
NTE_BAD_PROV_TYPE | The value of the dwProvType parameter is out of range. All provider types must be from 1 to 999, inclusive.
NTE_BAD_SIGNATURE | The provider DLL signature could not be verified. Either the DLL or the digital signature has been tampered with.
NTE_EXISTS | The dwFlags parameter is CRYPT_NEWKEYSET, but the key container already exists.
NTE_KEYSET_ENTRY_BAD | The registry entry for the pszContainer key container was found (in the HKEY_CURRENT_USER window), but is corrupt. See System Administration for details about the CryptoAPI registry usage.
NTE_KEYSET_NOT_DEF | No registry entry exists in the HKEY_CURRENT_USER window for the key container specified by pszContainer.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.
NTE_PROV_DLL_NOT_FOUND | The provider DLL file does not exist or is not on the current path.
NTE_PROV_TYPE_ENTRY_BAD | The registry entry for the provider type specified by dwProvType is corrupt. This error may relate to either the user default CSP list or the machine default CSP list. See System Administration for details about the CryptoAPI registry usage.
NTE_PROV_TYPE_NO_MATCH | The provider type specified by dwProvType does not match the provider type found in the registry. Note that this error can only occur when pszProvider specifies an actual CSP name.
NTE_PROV_TYPE_NOT_DEF | No registry entry exists for the provider type specified by dwProvType.
NTE_PROVIDER_DLL_FAIL | The provider DLL file could not be loaded, and may not exist. If it exists, then the file is not a valid DLL.
NTE_SIGNATURE_FILE_BAD | An error occurred while loading the DLL file image, prior to verifying its signature.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
BYTE pbData[1000];
DWORD cbData;

// Get a handle to the default PROV_RSA_FULL provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    return;
}

// Read the name of the default CSP.
cbData = 1000;
if(!CryptGetProvParam(hProv, PP_NAME, pbData, &cbData, 0)) {
    printf("Error %x reading CSP name!\n", GetLastError());
    return;
}
printf("Provider name: %s\n", pbData);

// Read the name of the default key container.
cbData = 1000;
if(!CryptGetProvParam(hProv, PP_CONTAINER, pbData, &cbData, 0)) {
    printf("Error %x reading key container name!\n", GetLastError());
    return;
}
printf("Key Container name: %s\n", pbData);

// Perform cryptographic operations.
...

// Release the provider handle.
if(!CryptReleaseContext(hProv, 0)) {
    printf("Error %x during CryptReleaseContext!\n", GetLastError());
    return;
}

// ****************************************************************

// Get a handle to the Microsoft Base Cryptographic Provider and the
// "KC1" key container.
if(!CryptAcquireContext(&hProv, TEXT("KC1"), MS_DEF_PROV,
                        PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    return;
}

// Perform cryptographic operations.
...

// Release the provider handle.
if(!CryptReleaseContext(hProv, 0)) {
    printf("Error %x during CryptReleaseContext!\n", GetLastError());
    return;
}

// ****************************************************************

// Get a handle to the default provider. Create a new key container
// named "KC2". Note that this key container will be empty until keys
// are explicitly created with the CryptGenKey function.
lstrcpy(szProv, );
lstrcpy(szContainer, );
if(!CryptAcquireContext(&hProv, TEXT("KC2"), NULL, PROV_RSA_FULL,
                        CRYPT_NEWKEYSET)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    return;
}

// Perform cryptographic operations.
...

// Release the provider handle.
if(!CryptReleaseContext(hProv, 0)) {
    printf("Error %x during CryptReleaseContext!\n", GetLastError());
    return;
}

For more examples, see Hashed Message Example Code, Enveloped Message Example 1, Enveloped Message Example 2, Sender Code Example, and Example Code Using CryptEncryptMessage.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptGenKey, CryptGetProvParam, CryptReleaseContext


CryptContextAddRef

The CryptContextAddRef function is used to add one to the reference count on a HCRYPTPROV handle.

#include <wincrypt.h>
BOOL WINAPI CryptContextAddRef(
  HCRYPTPROV hProv,      // in
  DWORD *pdwReserved,    // in
  DWORD dwFlags          // in
);

Parameters

hProv
HCRYPTPROV handle for which the reference count is being incremented.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.

Remarks

CryptContextAddRef is used to increase the reference count on a HCRYPTPROV handle so that multiple calls to CryptReleaseContext are required to actually release the handle.

Example

HCRYPTPROV    hProv = 0;

// Acquire a context handle
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_SIG, 0)) {
   printf("Error %x during CryptAcquireContext!\n", GetLastError);
   return;
}

if (!CryptContextAddRef(&hProv, NULL, 0)) {
   printf("Error %x during CryptContextAddRef!\n", GetLastError);
   return;
}

...

// The first call to CryptReleaseContext will not release the provider handle
// since the reference count has been bumped up.
if (!CryptReleaseContext(hProv, 0)) {
   printf("Error %x during CryptReleaseContext!\n", GetLastError);
   return;
}

// Release the provider handle.
if (!CryptReleaseContext(hProv, 0)) {
   printf("Error %x during CryptReleaseContext!\n", GetLastError);
   return;
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptReleaseContext


CryptCreateHash

The CryptCreateHash function is used to initiate the hashing of a stream of data. It returns to the caller a handle to a CSP hash object. This handle can also be used in subsequent calls to CryptHashData and CryptHashSessionKey in order to hash streams of data and session keys.

#include <wincrypt.h>
BOOL WINAPI CryptCreateHash(
  HCRYPTPROV hProv,    // in
  ALG_ID Algid,        // in
  HCRYPTKEY hKey,      // in
  DWORD dwFlags,       // in
  HCRYPTHASH *phHash   // out
);

Parameters

hProv
Handle to the CSP to use. An application obtains this handle by using the CryptAcquireContext function.
Algid
Algorithm identifier of the hash algorithm to use.

The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for the list of default algorithms.

hKey
If the type of hash algorithm is a keyed hash, such as the HMAC or MAC algorithm, the key for the hash should be passed in this parameter. For nonkeyed algorithms, this parameter should be set to zero.

For keyed algorithms, the key must be to a block cipher, such as RC2, that has a cipher mode of CBC.

dwFlags
Flag values. This parameter is reserved for future use and should always be zero.
phHash
Address to which the function copies a handle to the new hash object.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory during the operation.
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_KEY | A keyed hash algorithm (such as CALG_MAC) is specified by Algid and the hKey parameter is either zero or it specifies an invalid key handle. This error code will also be returned if the key is to a stream cipher, or if the cipher mode is anything other than CBC.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Remarks

The Microsoft Base Cryptographic Provider defines the following hashing algorithms.

Constant | Description
CALG_HMAC | HMAC, a keyed hash algorithm
CALG_MAC | Message Authentication Code
CALG_MD2 | MD2
CALG_MD5 | MD5
CALG_SHA | US DSA Secure Hash Algorithm
CALG_SHA1 | Same as CALG_SHA
CALG_SSL3_SHAMD5 | SSL3 client authentication

More information on hashing algorithms can be found under Hashing and Signature Algorithms and in the pages subsequent to it.

The computation of the actual hash is done with the CryptHashData and CryptHashSessionKey functions. These require a handle to the hash object. After all the data has been added to the hash object, any of the following operations can be performed:

  • The hash value can be retrieved by using CryptGetHashParam.
  • A session key can be derived by using CryptDeriveKey.
  • The hash can be signed by using CryptSignHash.
  • A signature can be verified by using CryptVerifySignature.

After one of the functions from this list has been called, CryptHashData and CryptHashSessionKey may not be called.

Example

See CryptHashSessionKey

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptDeriveKey, CryptDestroyHash, CryptGetHashParam, CryptHashData, CryptHashSessionKey, CryptSetHashParam, CryptSignHash, CryptVerifySignature, Hashing and Signature Algorithms


CryptDecrypt

The CryptDecrypt function is used to decrypt data that was previously encrypted by using the CryptEncrypt function.

Important changes have been made to the CryptoAPI in order to support S/MIME e-mail interoperability, which affect the handling of enveloped messages. See the Remarks for CryptMsgOpenToEncode for details.

Due to French import laws, the Microsoft CSPs do not allow encryption when the Microsoft® Windows NT® operating system is used in France. Therefore, under this condition, this function will fail with the error NTE_PERM.

#include <wincrypt.h>
BOOL WINAPI CryptDecrypt(
  HCRYPTKEY hKey,    // in
  HCRYPTHASH hHash,  // in
  BOOL Final,        // in
  DWORD dwFlags,     // in
  BYTE *pbData,      // in/out
  DWORD *pcbData     // in/out
);

Parameters

hKey
A handle to the key to use for the decryption. An application obtains this handle by using either the CryptGenKey or CryptImportKey function.

This key specifies the decryption algorithm that is used.

hHash
A handle to a hash object. This parameter is used only if a hash of the data is to be computed. See the "Remarks" section for more information.

If no hash is to be done, this parameter must be zero.

Final
The Boolean value that specifies whether this is the last section in a series being decrypted. This will be TRUE if this is the last or only block. If it is not, then it will be FALSE. See the "Remarks" section for more information.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
pbData
The buffer holding the data to be decrypted. After the decryption has been performed, the plaintext is placed back in this same buffer.

The number of encrypted bytes in this buffer is specified by pcbData.

pcbData
The address of the data length. Before calling this function, the caller should set this parameter to the number of bytes to be decrypted. Upon return, this address will contain the number of bytes of plaintext generated.

When a block cipher is used, this data length must be a multiple of the block size, unless this is the final section of data to be decrypted and the Final flag is TRUE.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The hKey session key specifies an algorithm that this CSP does not support.
NTE_BAD_DATA | The data to be decrypted is invalid. For example, when a block cipher is used and the Final flag is FALSE, the value specified by pcbData must be a multiple of the block size. This error can also be returned when the padding is found to be invalid.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hHash parameter contains an invalid handle.
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a key.
NTE_BAD_LEN | The size of the output buffer is too small to hold the generated plaintext.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot be found.
NTE_DOUBLE_ENCRYPT | The application attempted to decrypt the same data twice.
NTE_FAIL | The function failed in some unexpected way.

Remarks

If data is to be decrypted and hashed simultaneously, a handle to a hash object can be passed in the hHash parameter. The hash value will be updated with the decrypted plaintext. This option is useful when simultaneously decrypting and verifying a signature.

Before calling CryptDecrypt, the application should obtain a handle to the hash object by calling the CryptCreateHash function. After the decryption is complete, the hash value can be obtained (through CryptGetHashParam), it can be signed (through CryptSignHash), or it can be used to verify a digital signature (through CryptVerifySignature).

When a large amount of data needs to be decrypted, it can be done in sections. This is done by calling CryptDecrypt repeatedly. The Final parameter should be set to TRUE only on the last invocation of CryptDecrypt, so the decryption engine can properly finish the decryption process. The following extra actions are performed when Final is TRUE:

  • If the key is a block cipher key, the data will be padded to a multiple of the block size of the cipher. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN parameter of the key.
  • If the cipher is operating in a chaining mode, the next CryptDecrypt operation will reset the cipher's feedback register to the KP_IV value of the key.
  • If the cipher is a stream cipher, the next CryptDecrypt call will reset the cipher to its initial state.

Example

See Encrypting and Decrypting Data.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptEncrypt, CryptGenKey, CryptGetKeyParam, CryptGetHashParam, CryptImportKey, CryptSignHash, CryptVerifySignature


CryptDeriveKey

The CryptDeriveKey function generates cryptographic keys derived from base data. This function guarantees that all keys generated from the same base data will be identical, provided the same CSP and algorithms are used. The base data can be a password or any other user data.

This function is the same as CryptGenKey, except that the generated session keys are derived from base data instead of being random. Another difference is that the CryptDeriveKey function cannot be used to generate public/private key pairs.

A handle to the session key is returned in phKey. This handle can then be used as needed with any of the other CryptoAPI functions that require key handles.

#include <wincrypt.h>
BOOL WINAPI CryptDeriveKey(
  HCRYPTPROV hProv,      // in
  ALG_ID Algid,          // in
  HCRYPTHASH hBaseData,  // in
  DWORD dwFlags,         // in
  HCRYPTKEY *phKey       // in/out
);

Parameters

hProv
A handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
Algid
The identifier for the algorithm for which the key is to be generated.

The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for a list of possible algorithm identifiers.

hBaseData
A handle to a hash object that has been fed the exact base data.

To obtain this handle, an application must first create a hash object with CryptCreateHash and then add the base data to the hash object with CryptHashData. This process is described in detail in Hashes and Digital Signatures.

dwFlags
The flags specifying the type of key generated. This parameter can be zero, or you can specify one or more of the following flags by using the bitwise OR operator to combine them:
  • CRYPT_EXPORTABLE. If this flag is set, then the session key can be transferred out of the CSP into a key blob through the CryptExportKey function. Because keys generally must be exportable, this flag should usually be set.

    If this flag is not set, then the session key will not be exportable. This means the key will be available only within the current session and only the application that created it will be able to use it.

    This flag does not apply to public/private key pairs.

  • CRYPT_CREATE_SALT. Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value is 128 bits and the session key is 40 bits, there will be 88 bits left over.

    If this flag is set, then the key will be assigned a salt value based on the unused hash value bits. You can retrieve this salt value by using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT.

    If this flag is not set, then the key will be given a salt value of zero.

    When keys with nonzero salt values are exported (by using CryptExportKey), the salt value must also be obtained and kept with the key blob.

  • CRYPT_NO_SALT. Specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft Cryptographic Providers— Release Notes.
  • CRYPT_USER_PROTECTED. If this flag is set, then the user will be notified through a dialog box or another method when certain actions are attempted by using this key. The precise behavior is specified by the CSP being used. Prior to Microsoft Internet Explorer 4.0, Microsoft Cryptographic Providers ignore this flag. Starting with Microsoft Internet Explorer 4.0, Microsoft Providers support this flag value.
  • CRYPT_UPDATE_KEY. Some CSPs use session keys that are derived from multiple hash values. When this is the case, CryptDeriveKey must be called multiple times.

    If this flag is set, a new session key is not generated. Instead, the key specified by phKey is modified. The precise behavior of this flag is dependent on the type of key being generated and on the particular CSP being used.

    The Microsoft Cryptographic Providers ignore this flag.

phKey
The address to which the function copies the handle of the newly generated key.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_HASH | The hBaseData parameter does not contain a valid handle to a hash object.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_FAIL | The function failed in some unexpected way.

Remarks

To generate a key for a symmetric encryption algorithm, use the Algid parameter to specify the algorithm. The algorithms available will most likely be different for each CSP. If you are using the Microsoft Base Cryptographic Provider, use one of the following values to specify the algorithm.

Value | Description
CALG_RC2 | RC2 block cipher
CALG_RC4 | RC4 stream cipher

When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk-encrypting data. To change these parameters, use the CryptSetKeyParam function.

After the CryptDeriveKey function has been called, no more data can be added to the hash object. The CryptDestroyHash function should be called at this point to destroy the hash object.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
HCRYPTHASH hHash = 0;
CHAR szPassword[ ] = "apple-camshaft";
DWORD dwLength;

// Get a handle to user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
    printf("Error %x during CryptCreateHash!\n", GetLastError());
    goto done;
}

// Hash the password string.
dwLength = strlen(szPassword);
if(!CryptHashData(hHash, (BYTE *)szPassword, dwLength, 0)) {
    printf("Error %x during CryptHashData!\n", GetLastError());
    goto done;
}

// Create a block cipher session key based on the hash of the password.
if(!CryptDeriveKey(hProv, CALG_RC2, hHash, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptDeriveKey!\n", GetLastError());
    goto done;
}

// Use 'hKey' to encrypt or decrypt a message.
...

done:

// Destroy the hash object.
if(hHash != 0) CryptDestroyHash(hHash);

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptCreateHash, CryptDestroyHash, CryptDestroyKey, CryptExportKey, CryptGenKey, CryptGetKeyParam, CryptHashData, CryptSetKeyParam


CryptDestroyHash

The CryptDestroyHash function destroys the hash object referenced by the hHash parameter. After a hash object has been destroyed, it can no longer be used and its handle is useless from then on.

All hash objects should be destroyed with the CryptDestroyHash function when the application is finished with them.

#include <wincrypt.h>
BOOL WINAPI CryptDestroyHash(
  HCRYPTHASH hHash       // in
);

Parameters

hHash
Handle to the hash object to be destroyed.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_BUSY | The hash object specified by hHash is currently being used by another process.
ERROR_INVALID_HANDLE | The hHash parameter specifies an invalid handle.
ERROR_INVALID_PARAMETER | The hHash parameter contains an invalid value.
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot be found.

Remarks

When a hash object is destroyed, many CSPs will scrub the memory in the CSP where the hash object was held. The CSP memory is then freed.

There should be a one-to-one correspondence between calls to CryptCreateHash and CryptDestroyHash.

Example

See CryptHashSessionKey.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptHashData, CryptSignHash


CryptDestroyKey

The CryptDestroyKey function releases the handle referenced by the hKey parameter. After a key handle has been released, it becomes invalid and cannot be used again.

If the handle refers to a session key, or to a public key that has been imported into the CSP through CryptImportKey, this function destroys the key and frees the memory that the key occupied. Many CSPs will scrub the memory where the key was held before freeing it.

On the other hand, if the handle refers to a public/private key pair (obtained from CryptGetUserKey), the underlying key pair is not destroyed by this function. Only the handle is destroyed.

#include <wincrypt.h>
BOOL WINAPI CryptDestroyKey(
  HCRYPTKEY hKey     // in
);

Parameters

hKey
Handle to the key to be destroyed.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | The hKey parameter specifies an invalid handle.
ERROR_INVALID_PARAMETER | The hKey parameter contains an invalid value.
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a key.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot be found.

Remarks

Keys take up memory in both the operating system's memory space and the CSP's memory space. Some CSPs will be implemented in hardware with very limited memory resources. For this reason, it is important that applications destroy all keys with the CryptDestroyKey function when they are finished with them.

Example

See CryptHashSessionKey.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptDeriveKey, CryptGenKey, CryptGetUserKey, CryptImportKey


CryptDuplicateHash

The CryptDuplicateHash function is used to make an exact copy of a hash and the state the hash is in.

#include <wincrypt.h>
BOOL WINAPI CryptDuplicateHash(
  HCRYPTHASH hHash,    // in
  DWORD *pdwReserved,  // in
  DWORD dwFlags,       // in
  HCRYPTHASH phHash    // out
);

Parameters

hHash
Handle to the hash to be duplicated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.
phHash
The address of the handle to the duplicated hash.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_CALL_NOT_IMPLEMENTED | Since this is a new function, existing CSPs may not implement it. This error is returned if the CSP does not support this function.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_HASH | The handle to the original hash is not valid.

Remarks

CryptDuplicateHash is used to make copies of hashes and the exact state of the hash. An example of how this function might be used is that a caller may want to generate two hashes, but both hashes have to start with some common data hashed. A hash could be created, the common data hashed, a duplicate made with the CryptDuplicateHash function, and then the data unique to each hash would be hashed.

CryptDestroyHash must be called to destroy any hashes that are created with CryptDuplicateHash. Destroying the original hash does not cause the duplicate hash to be destroyed. Once a duplicate hash is made it is separate from the original hash. There is no shared state between the two hashes.

Example

HCRYPTPROV   hProv = 0;
HCRYPTHASH   hOriginalHash = 0;
HCRYPTHASH   hDuplicateHash = 0;
DWORD        dwErr;

// Create a hash.
if (!CryptCreateHash(hProv, CALG_SHA1, 0, &hOriginalHash))
   {printf("ERROR - CryptCreateHash: %X\n", GetLastError());
    return;}

// Hash common data.
if (!CryptHashData(hOriginalHash, (BYTE*)"Common Data", sizeof("Common Data"), 0))
   {printf("ERROR - CryptHashData: %X\n", GetLastError());
    return;}

// Duplicate the hash.
if (!CryptDuplicateHash(hOriginalHash, NULL, 0, &hDuplicateHash))
   {printf("ERROR - CryptDuplicateHash: %X\n", GetLastError());
   return;}

// Hash some data with the original hash.
if (!CryptHashData(hOriginalHash, (BYTE*)"Some Data", sizeof("Some Data"), 0))
   {printf("ERROR - CryptHashData: %X\n", GetLastError());
   return;}

// Hash other data with the duplicate hash.
if (!CryptHashData(hDuplicateHash, (BYTE*)"Other Data", sizeof("Other Data"), 0))
   {printf("ERROR - CryptHashData: %X\n", GetLastError());
    return;}

...

// Destroy the original hash.
if (!CryptDestroyHash (hOriginalHash))
   {printf("ERROR - CryptDestroyHash: %X\n", GetLastError());
   return;}

// Destroy the duplicate hash.
if (!CryptDestroyHash(hDuplicateHash))
   {printf("ERROR - CryptDestroyHash: %X\n", GetLastError());
    return;}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptDestroyHash


CryptDuplicateKey

The CryptDuplicateKey function is used to make an exact copy of a key and the state the key is in. Some keys have an associated state, for example an initialization vector and/or a salt value.

#include <wincrypt.h>
BOOL WINAPI CryptDuplicateKey(
  HCRYPTKEY hKey,      // in
  DWORD *pdwReserved,  // in
  DWORD dwFlags,       // in
  HCRYPTKEY* phKey     // out
);

Parameters

hKey
The handle to the key to be duplicated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
phKey
The address of the handle to the duplicated key.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_CALL_NOT_IMPLEMENTED | Since this is a new function, existing CSPs may not implement it. This error is returned if the CSP does not support this function.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_KEY | The handle to the original key is not valid.

Remarks

CryptDuplicateKey is used to make copies of keys and the exact state of the key. An example of how this function might be used is that a caller may want to encrypt two separate messages with the same key, but with different salt values. The key could be generated, a duplicate would be made with the CryptDuplicateKey function, and then the appropriate salt value would be set on each key with the CryptSetKeyParam function.

CryptDestroyKey must be called to destroy any keys that are created with CryptDuplicateKey. Destroying the original key does not cause the duplicate key to be destroyed. Once a duplicate key is made, it is separate from the original key. There is no shared state between the two keys.

Example

HCRYPTPROV   hProv = 0;
HCRYPTKEY    hOriginalKey = 0;
HCRYPTKEY    hDuplicateKey = 0;
DWORD        dwErr;

// Generate a key.
if (!CryptGenKey(hProv, CALG_RC4, 0, &hOriginalKey))
   {printf("ERROR - CryptGenKey: %X\n", GetLastError());
    return;}

// Duplicate the key.
if (!CryptDuplicateKey(hOriginalKey, NULL, 0, &hDuplicateKey))
   {printf("ERROR - CryptDuplicateKey: %X\n", GetLastError());
    return;}

...

// Destroy the original key.
if (!CryptDestroyKey(hOriginalKey))
   {printf("ERROR - CryptDestroyKey: %X\n", GetLastError());
   return;}

// Destroy the duplicate key.
if (!CryptDestroyKey(hDuplicateKey))
   {printf("ERROR - CryptDestroyKey: %X\n", GetLastError());
   return;}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptDestroyKey


CryptEncrypt

The CryptEncrypt function is used to encrypt data. The algorithm used to encrypt the data is designated by the key held by the CSP module, which is referenced by the hKey parameter.

Important changes have been made to the CryptoAPI in order to support S/MIME e-mail interoperability, which affect the handling of enveloped messages. See the Remarks for CryptMsgOpenToEncode for details.

Due to French import laws, the Microsoft CSPs do not allow encryption when the Microsoft® Windows NT® operating system is used in France. Therefore, under this condition, this function will fail with the error NTE_PERM.

#include <wincrypt.h>
BOOL WINAPI CryptEncrypt(
  HCRYPTKEY hKey,   // in
  HCRYPTHASH hHash, // in
  BOOL Final,       // in
  DWORD dwFlags,    // in
  BYTE *pbData,     // in/out
  DWORD *pcbData,   // in/out
  DWORD cbBuffer    // in
);

Parameters

hKey
A handle to the key to use for the encryption. An application obtains this handle by using either the CryptGenKey or the CryptImportKey function.

This key specifies the encryption algorithm that is used.

hHash
A handle to a hash object. This parameter is used only if a hash of the data is to be computed at the same time the encryption is being performed. See the "Remarks" section for more information.

If no hash is to be done, this parameter must be zero.

Final
The Boolean value that specifies whether this is the last section in a series being encrypted. This should be TRUE if this is the last or only block, and FALSE if it is not. See the "Remarks" section for more information.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
pbData
The buffer holding the data to be encrypted. After the encryption has been performed, the encrypted data is placed back in this same buffer.

The size of this buffer is specified by cbBuffer. The number of bytes of data to be encrypted is specified by pcbData.

This parameter can be NULL if all you are doing is determining the number of bytes required for the returned data.

pcbData
The address of the data length. Before calling this function, the caller should set this parameter to the number of bytes to be encrypted. Upon return, this address will contain the number of bytes of encrypted data.

If the buffer specified by pbData is not large enough to hold the data, the function returns the ERROR_MORE_DATA error code (through GetLastError) and stores the required buffer size, in bytes, into the variable pointed to by pcbData.

If pbData is NULL, then no error is returned, and the function stores the size of the data, in bytes, in the variable pointed to be pcbData. This lets an application determine the correct buffer size unambiguously.

When a block cipher is used, this data length must be a multiple of the block size, unless this is the final section of data to be encrypted and the Final flag is TRUE.

cbBuffer
The number of bytes in the pbData buffer.

Note that, depending on the algorithm used, the encrypted text can be slightly larger than the original plaintext. In this case, the pbData buffer needs to be sized accordingly.

As a rule, if a stream cipher is used the ciphertext will be the same size as the plaintext. If a block cipher is used, the ciphertext will be up to a "block length" larger than the plaintext.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The hKey session key specifies an algorithm that this CSP does not support.
NTE_BAD_DATA | The data to be encrypted is invalid. For example, when a block cipher is used and the Final flag is FALSE, the value specified by pcbData must be a multiple of the block size.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hHash parameter contains an invalid handle.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a key.
NTE_BAD_LEN | The size of the output buffer is too small to hold the generated ciphertext.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot be found.
NTE_DOUBLE_ENCRYPT | The application attempted to encrypt the same data twice.
NTE_FAIL | The function failed in some unexpected way.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Remarks

If data is to be hashed and encrypted simultaneously, a handle to a hash object can be passed in the hHash parameter. The hash value will be updated with the plaintext passed in. This option is useful when generating signed and encrypted text.

Before calling CryptEncrypt, the application should obtain a handle to the hash object by calling the CryptCreateHash function. After the encryption is complete, the hash value can be obtained through the CryptGetHashParam function or the hash can be signed using the CryptSignHash function.

When a large amount of data needs to be encrypted, it can be done in sections. This is done by calling CryptEncrypt repeatedly. The Final parameter should be set to TRUE only on the last invocation of CryptEncrypt, so the encryption engine can properly finish the encryption process. The following extra actions are performed when Final is TRUE:

  • If the key is a block cipher key, the data will be padded to a multiple of the block size of the cipher. To find the block size of a cipher, use CryptGetKeyParam to get the KP_BLOCKLEN parameter of the key.
  • If the cipher is operating in a chaining mode, the next CryptEncrypt operation will reset the cipher's feedback register to the KP_IV value of the key.
  • If the cipher is a stream cipher, the next CryptEncrypt will reset the cipher to its initial state.

Example

See Encrypting and Decrypting Data.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptDecrypt, CryptGenKey, CryptGetHashParam, CryptImportKey, CryptSignHash


CryptEnumProviders

The CryptEnumProviders function is used to enumerate the providers on a machine.

#include <wincrypt.h>
BOOL WINAPI CryptEnumProviders(
  DWORD dwIndex,        // in
  DWORD *pdwReserved,   // in
  DWORD dwFlags,        // in
  DWORD *pdwProvType,   // out
  LPTSTR pszProvName,   // out
  DWORD *pcbProvName    // in/out
);

Parameters

dwIndex
The index of the next provider to be enumerated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
pdwProvType
The address of the DWORD value designating the type of the enumerated provider.
pszProvName
Pointer to a buffer that receives the data from the enumerated provider. This is a string including the terminating NULL character.

This parameter can be NULL to set the size of the name for memory allocation purposes. For more information, see the "Common In/Out Parameter Conventions" section at the beginning of this Reference.

pcbProvName
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pszProvName parameter. When the function returns, the variable pointed to by the pcbProvName parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pszProvName is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_MORE_DATA | The pszProvName buffer was not large enough to hold the provider name.
ERROR_NO_MORE_ITEMS | There are no more items to enumerate.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory.
NTE_BAD_FLAGS | dwFlags has an unrecognized value.
NTE_FAIL | Something was wrong with the type registration.

Remarks

CryptEnumProviders is used to enumerate the providers on a machine. The provider types may be enumerated by using CryptEnumProviderTypes.

Example

long       i;
LPTSTR     pszName;
DWORD      cbName;
DWORD      dwErr;

// Loop through enumerating provider types.
for (i=0;;i++)
{
if (!CryptEnumProviders(i, NULL, 0, &dwType, NULL, &cbName))
    {if (ERROR_NO_MORE_ITEMS != (dwErr = GetLastError()))
        {printf("ERROR - CryptEnumProviderTypes : %X\n", dwErr);
        }
     break;
    }

if (NULL == pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
   {printf("ERROR – LocalAlloc failed!\n");
   }

if (!CryptEnumProviders(i, NULL, 0, &dwType, pszName, &cbName))
   {if (ERROR_NO_MORE_ITEMS != (dwErr = GetLastError()))
       {printf("ERROR - CryptEnumProviderTypes : %X\n", dwErr);
       }
    LocalFree(pszName);
    break;
   }
printf ("Provider %s is type %d\n", pszName, dwType);
LocalFree(pszName);
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptEnumProviderTypes


CryptEnumProviderTypes

The CryptEnumProviderTypes function is used to enumerate the types of providers supported on the machine.

#include <wincrypt.h>
BOOL WINAPI CryptEnumProviderTypes(
  DWORD dwIndex,        // in
  DWORD *pdwReserved,   // in
  DWORD dwFlags,        // in
  DWORD *pdwProvType,   // out
  LPTSTR pszTypeName,   // out
  DWORD *pcbTypeName    // in/out
);

Parameters

dwIndex
The index of the next provider type to be enumerated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
pdwProvType
The address of the DWORD value designating the enumerated provider type.
pszTypeName
Pointer to a buffer that receives the data from the enumerated provider type. This is a string including the terminating NULL character. There are provider types which may not have friendly names and in this case no name will be returned and the returned value pointed to by pcbTypeName will be 0.

This parameter can be NULL if you want to get the size of the name for memory allocation purposes. For more information, see the "Common In/Out Parameter Conventions" section at the beginning of this Reference.

pcbTypeName
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pszTypeName parameter. When the function returns, the variable pointed to by the pcbTypeName parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pszTypeName is NULL. There are provider types which may not have friendly names and in this case no name will be returned and the returned value pointed to by pcbTypeName will be 0.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_NO_MORE_ITEMS | There are no more items to enumerate.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory.
NTE_BAD_FLAGS | dwFlags has an unrecognized value.
NTE_FAIL | Something was wrong with the type registration.

Remarks

CryptEnumProviderTypes is used to enumerate the provider types on a machine. Once this is done, the providers for a specific type may be enumerated by using CryptEnumProviders.

Example

long   i;
DWORD  dwErr;

// Loop through enumerating provider types.
for (i=0;;i++)
{
if (!CryptEnumProviderTypes(i, NULL, 0, &dwType, NULL, NULL))
   {if (ERROR_NO_MORE_ITEMS != (dwErr = GetLastError()))
       {printf("ERROR - CryptEnumProviderTypes : %X\n", dwErr);
       }
    break;
   }
printf ("Provider Type %d\n", dwType);
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptEnumProviders


CryptExportKey

The CryptExportKey function is used to export cryptographic keys out of a cryptographic service provider in a secure manner.

A handle to the key to be exported is passed into the function and the function returns a key blob to the caller. This key blob can be sent over a nonsecure transport or stored in a nonsecure storage location. The key blob is useless until the intended recipient uses the CryptImportKey function on it, which will then import the key into the recipient's CSP.

#include <wincrypt.h>
BOOL WINAPI CryptExportKey(
  HCRYPTKEY hKey,     // in
  HCRYPTKEY hExpKey,  // in
  DWORD dwBlobType,   // in
  DWORD dwFlags,      // in
  BYTE *pbData,       // out
  DWORD *pcbDataLen   // in/out
);

Parameters

hKey
Handle to the key to be exported.
hExpKey
Handle to a cryptographic key belonging to the destination user. The key data within the key blob created is encrypted by using this key. This ensures that only the destination user will be able to make use of the key blob.

Most often, this will be the key exchange public key of the destination user. However, certain protocols in some CSPs require that a session key belonging to the destination user be used for this purpose. (Neither the Microsoft Base Cryptographic Provider or the Microsoft Enhanced Cryptographic Provider currently support this.)

If the key blob type specified by dwBlobType is PUBLICKEYBLOB, then this parameter is unused and should be set to zero.

If the key blob type specified by dwBlobType is PRIVATEKEYBLOB, then this is typically a handle to a session key that is to be used to encrypt the key blob. Some CSPs allow this parameter to be zero, in which case the application should encrypt the private key blob manually so as to protect it.

To determine how Microsoft Cryptographic Providers respond to this parameter, see The Private-Key Blob sections of Microsoft Cryptographic Service Providers .

dwBlobType
Type of key blob to be exported. This must be one of the following constants, which are discussed in Exchanging Cryptographic Keys:
  • SIMPLEBLOB - used to transport session keys
  • PUBLICKEYBLOB - used to transport public keys
  • PRIVATEKEYBLOB - used to transport public/private key pairs
  • OPAQUEBLOB - used to store session keys in a Schannel CSP. OPAQUEBLOBs are non-transferrable and must be used within the CSP that generated the blob.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.
pbData
Pointer to a buffer that receives the key blob.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbDataLen
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbDataLen parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbDataLen is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbDataLen.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_KEY | One or both of the keys specified by hKey and hExpKey are invalid.
NTE_BAD_KEY_STATE | You do not have permission to export the key. That is, when the hKey key was created, the CRYPT_EXPORTABLE flag was not specified.
NTE_BAD_PUBLIC_KEY | The key blob type specified by dwBlobType is PUBLICKEYBLOB, but hExpKey does not contain a public key handle.
NTE_BAD_TYPE | The dwBlobType parameter specifies an unknown blob type.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot be found.
NTE_NO_KEY | A session key is being exported and the hExpKey parameter does not specify a public key.

Example

#include <wincrypt.h>

HCRYPTPROV hProv;      // Handle to CSP
HCRYPTKEY hKey;        // Handle to session key
HCRYPTKEY hXchgKey;    // Handle to receiver's exchange public key
BYTE *pbKeyBlob = NULL;
DWORD dwBlobLen;
...
// Determine the size of the key blob and allocate memory.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen)) {
    printf("Error %x computing blob length!\n", GetLastError());
    ...
}
if((pbKeyBlob = malloc(dwBlobLen)) == NULL) {
    printf("Out of memory!\n");
    ...
}

// Export the key into a simple key blob.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen)) {
    printf("Error %x during CryptExportKey!\n", GetLastError());
    ...
}

Another example is located in Sender Code Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptImportKey


CryptFormatObject

[This is preliminary documentation and subject to change.]

The CryptFormatObject function formats the encoded data and returns a Unicode string in the allocated buffer according to the certificate encoding type.

#include <wincrypt.h>
BOOL WINAPI CryptFormatObject(
  DWORD dwCertEncodingType,     // in
  DWORD dwFormatType,           // in
  DWORD dwFormatStrType,        // in
  void *pFormatStruct,          // in
  LPCSTR lpszStructType,        // in
  const BYTE *pbEncoded,        // in
  DWORD cbEncoded,              // in
  void *pbFormat,               // out
  DWORD *pcbFormat              // in/out
);

Parameters

dwCertEncodingType
Type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

dwFormatType
Format type values. Not used. Set to 0.
dwFormatStrType
Structure format type values. This parameter can be zero, or you can specify one or more of the following flags by using the bitwise OR operator to combine them:

Currently defined values are shown in the following table:
Format value | Description
0 | Display the data in single line. Each subfield is concatenated with a ", " (see Remarks).
CRYPT_FORMAT_
STR_MULTI_LINE 		Display the data in multiple lines rather than the default of a single line display (see Remarks).
CRYPT_FORMAT_
STR_NO_HEX 		Disables the hex dump (see Remarks).

pFormatStruct
Pointer to the format of the structure. Not used. Set to NULL.
lpszStructType
Pointer to an OID defining the encoded data. If the high-order word of the lpszStructType parameter is zero, the low-order word specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

The following table is a listing of supported OIDs with the associated OID extension:
OID Name | OID
SPC_FINANCIAL_CRITERIA_OBJID | 1.3.6.1.4.1.311.2.1.27
SPC_SP_AGENCY_INFO_OBJID | 1.3.6.1.4.1.311.2.1.10
szOID_AUTHORITY_INFO_ACCESS | 1.3.6.1.5.5.7.1.1
szOID_AUTHORITY_KEY_IDENTIFIER2 | 2.5.29.35
szOID_BASIC_CONSTRAINTS2 | 2.5.29.19
szOID_CERT_POLICIES | 2.5.29.32
szOID_CRL_DIST_POINTS | 2.5.29.31
szOID_CRL_REASON_CODE | 2.5.29.21
szOID_ENHANCED_KEY_USAGE | 2.5.29.37
szOID_ISSUER_ALT_NAME2 | 2.5.29.18
szOID_KEY_ATTRIBUTES | 2.5.29.2
szOID_KEY_USAGE | 2.5.29.15
szOID_KEY_USAGE_RESTRICTION | 2.5.29.4
szOID_NEXT_UPDATE_LOCATION | 1.3.6.1.4.1.311.10.2
szOID_RSA_SMIMECapabilities | 1.2.840.113549.1.9.15
szOID_SUBJECT_ALT_NAME2 | 2.5.29.17
szOID_SUBJECT_KEY_IDENTIFIER | 2.5.29.14

pbEncoded
Pointer to the encoded data to be formatted. If lpszStructType is one of the OIDs listed above, the pbEncoded is the encoded extension.
cbEncoded
Size, in bytes, of the pbEncoded structure.
pbFormat
Pointer to a buffer that receives the formatted string. When the buffer that is specified is not large enough to receive the decoded structure, the function sets ERROR_MORE_DATA and stores the required buffer size, in bytes, into the variable pointed to by pcbFormat.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbFormat
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbFormat parameter. When the function returns, the variable pointed to by the pcbFormat parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbFormat is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Remarks

The default behavior of CryptFormatObject is to return single line display of the encoded data, that is, each subfield will be concatenated with a ", " on one line. If a user prefers to display the data in multiple line, set the flag CRYPT_FORMAT_STR_MULTI_LINE, that is, each subfield will be displayed on a separate line.

If there is no formatting routine installed or registered for the lpszStructType, the hex dump of the encoded BLOB Structure will be returned. A user can set the flag CRYPT_FORMAT_STR_NO_HEX to disable the hex dump.

Example

// EXAMPLE CODE FOR USING CryptFormatObject().
// Assume that a pointer to an encoded data structure
// (pbEncoded) is already known.

// Set up the variables.
DWORD dwCertEncodingType; // Type of encoding
DWORD dwFormatType;       // Format type
DWORD dwFormatStrType;    // Structure format flags
LPCSTR pFormatStruct;     // Pointer to structure format- set to NULL
LPCSTR  lpszStructType;   // Pointer to type of encoding
const BYTE *pbEncoded;    // Pointer to the encoded object to be read
                          //   and formatted
DWORD  cbEncoded;         // size of structure
BYTE *pbFormat;           // Pointer to the formatted string
DWORD  pcbFormat;
DWORD  cbFormat;          // size of the formated object
BOOL fResult;             // Return value- True if function successful
                          //   False if function fails

// initalize the pointers/ structure
cout<< "Begin initalization."<< endl;

fResult= CryptFormatObject(
           X509_ASN_ENCODING,          // in- dwCertEncodingType
           0,                          // in- dwFormatType set to 0
           CRYPT_FORMAT_STR_MULTI_LINE,// in- dwFormatStrType- print
                                       //   in multiple line format
           NULL,                       // in- FormatStruct set to NULL
           szOID_CERT_POLICIES,        // in- Structure name
           pbEncoded,                  // in- Pointer to data
                                       //   structure to be formatted
                                       //   initialized elsewhere
           1024,                       // in- size in bytes
           NULL,                       // out- set to NULL to allocate
                                       //   memory
           &cbFormat);                 // in/out- pbFormat size

if (!fResult){
 cout<< "First call to CryptFormatObject failed"<< endl;
}
else {
  cout<< "First call to CryptFormatObject successful"<< endl;
  pbFormat = (BYTE*)malloc (cbFormat);
  cout<< "memory allocated" << endl;

// Function call to format the object
fResult= CryptFormatObject(
           X509_ASN_ENCODING,          // in- dwCertEncodingType
           0,                          // in- dwFormatType set to 0
           CRYPT_FORMAT_STR_MULTI_LINE,// in- dwFormatStrType- print
                                       //   in multiple line format
           NULL,                       // in- FormatStruct set to NULL
           szOID_CERT_POLICIES,        // in- Structure name
           pbEncoded,                  // in- initialized elsewhere
           1024,                       // in- size in bytes
           pbFormat,                   // out- pbFormat
           &cbFormat);                 // in/out- pbFormat size

if (!fResult){
 cout<< "Second call to CryptFormatObject failed"<< endl;
    }
else {
  cout<< "Second call to CryptFormatObject successful"<< endl
      << "The string is "<< pbFormat<< endl
      << "size of pbFormat (cbFormat)= "<< cbFormat<< endl;
    }
free(pbFormat);

}
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGenKey

The CryptGenKey function generates random cryptographic keys for use with the CSP module. A handle to the key is returned in phKey. This handle can then be used as needed with any of the other CryptoAPI functions requiring key handles.

The calling application is required to specify the algorithm when calling this function. Because this algorithm type is kept bundled with the key, the application does not need to specify the algorithm later when the actual cryptographic operations are performed.

The maximum size of an RSA signature key has been bumped up to 16,384 bits.

#include <wincrypt.h>
BOOL WINAPI CryptGenKey(
  HCRYPTPROV hProv,  // in
  ALG_ID Algid,      // in
  DWORD dwFlags,     // in
  HCRYPTKEY *phKey   // out
);

Parameters

hProv
Handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
Algid
Identifier for the algorithm for which the key is to be generated.

The valid values for this parameter will vary, depending on the CSP that is used. See the "Remarks" section for a list of possible algorithm identifiers.

dwFlags
Flags specifying the type of key generated.

The sizes of RSA signature and key exchange keys may be set when the key is generated. The key size is set with the upper 16 bits of the dwFlags parameter and these 16 bits represent the length of the key (modulus) in bits. So if a 2048 bit RSA signature key is to be generated then the value 0x08000000 would be combined together with the dwFlags parameter in bitwise OR operation. Notice that the upper 16 bits of 0x08000000 is 0x0800, or 2048 in decimal notation. If none of the upper 16 bits are set, then the default key size is generated. If a key larger than the max (16,384 signature, 512 key exchange) or smaller than the min (384 sig and key exchange) is given, the call fails with ERROR_INVALID_PARAMETER. For the parameters and limitations of keys generated using Microsoft providers, see Microsoft Cryptographic Service Providers.

This parameter can be zero, or you can specify one or more of the following flags by using the bitwise OR operator to combine them:

  • CRYPT_EXPORTABLE. If this flag is set, then the key can be transferred out of the CSP into a key blob by using the CryptExportKey function. Because session keys generally must be exportable, this flag should usually be set when they are created.

    If this flag is not set, then the key will not be exportable. For a session key, this means that the key will be available only within the current session and only the application that created it will be able to use it. For a public/private key pair, this means that the private key cannot be transported or backed up.

    This flag applies only to session key and private key blobs. It does not apply to public keys, which are always exportable.

  • CRYPT_CREATE_SALT. If this flag is set, then the key will be assigned a random salt value automatically. You can retrieve this salt value by using the CryptGetKeyParam function with the dwParam parameter set to KP_SALT.

    If this flag is not set, then the key will be given a salt value of zero.

    When keys with nonzero salt values are exported (through CryptExportKey), then the salt value must also be obtained and kept with the key blob.

  • CRYPT_NO_SALT. Specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft Cryptographic Providers— Release Notes.
  • CRYPT_USER_PROTECTED. If this flag is set, then the user will be notified through a dialog box or another method when certain actions are attempted using this key. The precise behavior is specified by the CSP being used. Prior to Microsoft Internet Explorer 4.0, Microsoft Cryptographic Providers ignore this flag. Starting with Microsoft Internet Explorer 4.0, Microsoft Providers support this flag value.
  • CRYPT_PREGEN. Specifies an initial Diffie-Hellman or DSS key generation. Useful only with Diffie-Hellman/DSS CSPs.
phKey
Address to which the function copies the handle of the newly generated key.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_FAIL | The function failed in some unexpected way.

Remarks

To generate a key to be used with a symmetric encryption algorithm (that is, a session key), use the Algid parameter to specify the algorithm. The algorithms available will most likely be different for each CSP. If you are using the Microsoft Base Cryptographic Provider, one of the following values can be used to specify the algorithm.

Value | Description
CALG_RC2 | RC2 block cipher
CALG_RC4 | RC4 stream cipher

If you are using a Diffie-Hellman CSP, use one of the following values.

Value | Description
CALG_DH_SF | Specifies a "Store and Forward" Diffie-Hellman key.
CALG_DH_EPHEM | Specifies an "Ephemeral" Diffie-Hellman key.

When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk encrypting data. To change these parameters, use the CryptSetKeyParam function.

In addition to generating keys for symmetric algorithms, the CryptGenKey function can also generate keys for public-key algorithms. The use of public-key algorithms is restricted to key exchange and digital signatures. Each CryptoAPI client generally possesses one key pair for each of these operations. To generate one of these key pairs, set the Algid parameter to one of the following values.

Value | Description
AT_KEYEXCHANGE | Key exchange
AT_SIGNATURE | Digital signature

Note When key specifications AT_KEYEXCHANGE and AT_SIGNATURE are specified for the Algid parameter, the algorithm identifiers that are used to generate the key depend on the provider used. As a result, for these key specifications, the values returned from CryptGetKeyParam (when the KP_ALGID parameter is specified) depend on the provider used. See ALG_ID to determine which algorithm identifier is used by the different providers for the key specs AT_KEYEXCHANGE and AT_SIGNATURE.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;

// Get a handle to user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Create a block cipher session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptGenKey!\n", GetLastError());
    goto done;
}

// Use 'hKey' to encrypt or decrypt a message.
...

done:

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);
// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

Other examples are located in Encryption Example and Sender Code Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptDestroyKey, CryptExportKey, CryptGetKeyParam, CryptImportKey, CryptSetKeyParam


CryptGenRandom

The CryptGenRandom function fills a buffer with random bytes.

#include <wincrypt.h>
BOOL WINAPI CryptGenRandom(
  HCRYPTPROV hProv,  // in
  DWORD dwLen,       // in
  BYTE *pbBuffer     // in/out
);

Parameters

hProv
Handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
dwLen
Number of bytes of random data to be generated.
pbBuffer
Buffer the function copies the random data to. This buffer must be at least dwLen bytes in length.

Optionally, the application can fill this buffer with data to use as an auxiliary random seed. This is explained further in the "Remarks" section.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_FAIL | The function failed in some unexpected way.

Remarks

The data produced by this function is cryptographically random. It is far more random than the data generated by the typical random number generator such as the one shipped with your "C" compiler.

This function is often used to generate random initialization vectors and salt values.

Seeding the Random Number Generator

All software random number generators work in fundamentally the same way. They start with a random number, known as the seed, and then use an algorithm to generate a pseudo-random sequence of bits based on it. The most difficult part of this process is to get a seed that is truly random. This is usually based on user input latency, or the jitter from one or more hardware components.

If your application has access to a good random source, then it can fill the pbBuffer buffer with some amount of random data before calling CryptGenRandom. The CSP will then use this data to further randomize its internal seed. Failing to initialize the pbBuffer buffer before calling CryptGenRandom is acceptable.

Example

See CryptSetKeyParam.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptGenKey, CryptSetKeyParam


CryptGetDefaultProvider

The CryptGetDefaultProvider function is used to determine the default CSP either for the current user or the machine for a given provider type. The name of the default CSP for the type given in the dwProvType parameter is returned.

#include <wincrypt.h>
BOOL WINAPI CryptGetDefaultProvider(
  DWORD dwProvType,   // in
  DWORD *pdwReserved, // in
  DWORD dwFlags,      // in
  LPTSTR pszProvName, // out
  DWORD *pcbProvName  // in/out
);

Parameters

dwProvType
The provider type of the CSP specified by the pszProvName parameter.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values.
Flag value | Description
CRYPT_MACHINE_DEFAULT | Causes the machine default CSP of the given type to be returned.
CRYPT_USER_DEFAULT | Causes the user default CSP of the given type to be returned.

pszProvName
Pointer to a buffer that receives the name of the default CSP. This is a string including the terminating NULL character.

This parameter can be NULL to set the size of the name for memory allocation purposes. For more information, see the "Common In/Out Parameter Conventions" section at the beginning of this Reference.

pcbProvName
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pszProvName parameter. When the function returns, the variable pointed to by the pcbProvName parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pszProvName is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | The buffer for the name is not large enough.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory.
NTE_BAD_FLAGS | dwFlags has an unrecognized value.

Remarks

CryptGetDefaultProvider is used to determine which installed CSP is currently set as the default for the current user or the machine. This information will most often be used for display to the user.

Example

LPTSTR   pszName;
DWORD    cbName;

// Get the name of the default CSP specified for the PROV_RSA_SIG
// type for the machine.
cbName = 0;
if (!CryptGetDefaultProvider(PROV_RSA_SIG, NULL, CRYPT_MACHINE_DEFAULT,
        NULL, &cbName))
   {printf("Error %x during CryptGetDefaultProvider!\n", GetLastError);
   return;
   }

if (NULL == (pszProvName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
   {printf("Error during memory allocation\n");
    return;
   }

if (!CryptGetDefaultProvider(PROV_RSA_SIG, NULL, CRYPT_MACHINE_DEFAULT,
        NULL, &cbName))
   {printf("Error %x during CryptGetDefaultProvider!\n", GetLastError);
    return;
   }

// Display this information to the user
...

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptSetProviderEx, CryptSetProvider


CryptGetHashParam

The CryptGetHashParam function retrieves data that governs the operations of a hash object. The actual hash value can also be retrieved by using this function.

#include <wincrypt.h>
BOOL WINAPI CryptGetHashParam(
  HCRYPTHASH hHash, // in
  DWORD dwParam,    // in
  BYTE *pbData,     // out
  DWORD *pcbData,   // in/out
  DWORD dwFlags     // in
);

Parameters

hHash
Handle to the hash object on which to query parameters.
dwParam
Parameter number. See the "Remarks" section for a list of valid parameters.
pbData
Pointer to a buffer that receives the specified parameter data. The form of this data will vary, depending on the parameter number.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbData is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

dwFlags
Flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The CSP context that was specified when the hash was created cannot be found.

Remarks

The dwParam value can be set to one of the following hash parameter types:

  • HP_ALGID. The hash algorithm. The pbData buffer will contain an ALG_ID value indicating that the algorithm was specified when the hash object was created. See the CryptCreateHash function for a list of hash algorithms.
  • HP_HASHSIZE. The hash value size. The pbData buffer will contain a DWORD value indicating the number of bytes in the hash value. This value will usually be 16 or 20, depending on the hash algorithm.
  • Applications should retrieve this parameter just before the HP_HASHVAL parameter so the correct amount of memory can be allocated.
  • HP_HASHVAL. The hash value. The pbData buffer will contain the hash value or message hash for the hash object specified by hHash. This value is generated based on the data supplied earlier to the hash object through the CryptHashData and CryptHashSessionKey functions.

    After this parameter has been retrieved, the hash object is marked "finished" and no more data can be added to it.

Note Some CSPs may add additional parameters that can be queried through this function.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
BYTE *pbHash = NULL;
DWORD dwHashLen;
#define BUFFER_SIZE 256
BYTE pbBuffer[BUFFER_SIZE];
DWORD dwCount;
DWORD i;

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}
// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
    printf("Error %x during CryptBeginHash!\n", GetLastError());
    goto done;
}

// Fill the buffer with test data.
for(i = 0 ; i < BUFFER_SIZE ; i++) {
    pbBuffer[i] = (BYTE)i;
}

// Put the hash in buffer.
if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
    printf("Error %x during CryptHashData!\n", GetLastError());
    goto done;
}

// Read the hash value size and allocate memory.
dwCount = sizeof(DWORD);
if(!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE *)&dwHashLen,
                      &dwCount, 0)) {
    printf("Error %x during reading hash size!\n", GetLastError());
    goto done;
}
if((pbHash = malloc(dwHashLen)) == NULL) {
    printf("Out of memory!\n");
    goto done;
}

// Read the hash value.
if(!CryptGetHashParam(hHash, HP_HASHVAL, pbHash, &dwHashLen, 0)) {
    printf("Error %x during reading hash value!\n", GetLastError());
    goto done;
}

// Print the hash value.
for(i = 0 ; i < dwHashLen ; i++) {
    printf("%2.2x ",pbHash[i]);
}
printf("\n");

done:

// Free memory.
if(pbHash !=NULL) free(pbHash);

// Destroy the hash object.
if(hHash) CryptDestroyHash(hHash);
// Release the CSP handle.
if(hProv) CryptReleaseContext(hProv,0);

Another example is located in Sender Code Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptGetKeyParam, CryptHashData, CryptHashSessionKey, CryptSetHashParam


CryptGetKeyParam

The CryptGetKeyParam function retrieves data that govern the operations of a key. Note that in the Microsoft Cryptographic Service Providers, the base symmetric keying material is not obtainable by this function or any other function.

#include <wincrypt.h>
BOOL WINAPI CryptGetKeyParam(
  HCRYPTKEY hKey,  // in
  DWORD dwParam,   // in
  BYTE *pbData,    // out
  DWORD *pcbData,  // in/out
  DWORD dwFlags    // in
);

Parameters

hKey
Handle to the key on which to query parameters.
dwParam
Parameter number. See the "Remarks" section for a list of valid parameters.
pbData
Pointer to a buffer that receives the parameter data. The function will copy the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbData is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

dwFlags
Flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_KEY or NTE_NO_KEY | The key specified by the hKey parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot be found.

Remarks

For all key types, the dwParam value can be set to one of the following key parameter types.

Parameter type | Description
KP_ALGID | Key algorithm. The pbData buffer will contain an ALG_ID value indicating the algorithm that was specified when the key was created. Note that when key specifications AT_KEYEXCHANGE and AT_SIGNATURE are specified for the Algid parameter, the algorithm identifiers that are used to generate the key depend on the provider used. As a result, for these key specifications the values returned from CryptGetKeyParam (when the KP_ALGID parameter is specified) depend on the provider used. See ALG_ID to determine which algorithm identifier is used by the different providers for the key specifications AT_KEYEXCHANGE and AT_SIGNATURE.
KP_BLOCKLEN | If a session key is specified by hKey, this parameter returns the block length, in bits, of the cipher. The pbData buffer will contain a DWORD value indicating the block length. For stream ciphers, this value will always be zero. If a public/private key pair is specified by hKey, this parameter returns the key pair's encryption granularity in bits. For example, the Microsoft Base Cryptographic Provider generates 512-bit RSA key pairs, so a value of 512 is returned for these keys. If the public-key algorithm does not support encryption, the value returned by this parameter is undefined.
KP_KEYLEN | Used to get the actual length of a key in bits, The length of the key is located in the DWORD pointed to by pbData. This parameter can be used to get the length of any key type.
KP_SALT | The salt value. The pbData buffer will contain a BYTE array indicating the current salt value. The size of the salt value will vary depending on the CSP and algorithm being used. Salt values do not apply to public/private key pairs.
KP_PERMISSIONS | Key permissions. The pbData buffer will contain a DWORD value with zero or more permission flags set. Refer to the table at the end of this section for a description of each of these flags.

If a DSS key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

Parameter type | Description
KP_P | The pbData buffer will contain the prime modulus P from the DSS key blob. The length of the data is returned in the pcbData parameter.
KP_Q | The pbData buffer will contain the prime Q from the DSS key blob. The length of the data is returned in the pcbData parameter.
KP_G | The pbData buffer will contain the generator G from the DSS key blob. The length of the data is returned in the pcbData parameter.

If a block cipher session key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

Parameter type | Description
KP_EFFECTIVE_KEYLEN | Used to query the effective key length of an RC2 key. The value of the effective key length is returned as a DWORD pointed to by the pbData parameter.
KP_IV | The initialization vector. The pbData buffer will contain a BYTE array indicating the current initialization vector. This array contains block_length/8 elements. For example, if the block length is 64 bits, the initialization vector will consist of eight bytes.
KP_PADDING | The padding mode. The pbData buffer will contain a DWORD value indicating the padding method used by the cipher. Following are the padding modes currently defined: PKCS5_PADDING—PKCS 5 (sec 6.2) padding method.
KP_MODE | The cipher mode. The pbData buffer will contain a DWORD value indicating the mode of the cipher. Refer to the following table for a list of valid cipher modes.
KP_MODE_BITS | The number of bits to feed back. The pbData buffer will contain a DWORD value indicating the number of bits that are processed per cycle when the OFB or CFB cipher modes are used.

The following table lists the possible values for the KP_MODE parameter. These cipher modes are discussed in Encrypting and Decrypting Data.

Cipher mode | Description
CRYPT_MODE_ECB | Electronic codebook
CRYPT_MODE_CBC | Cipher block chaining
CRYPT_MODE_OFB | Output feedback mode
CRYPT_MODE_CFB | Cipher feedback mode

The following table lists the flags in the bit field that are obtained when the KP_PERMISSIONS parameter is read. These permission flags are ignored by the Microsoft Base Cryptographic Provider. However, custom CSPs can use these flags to restrict operations on keys.

Permission flag | Description
CRYPT_ENCRYPT | Allow encryption.
CRYPT_DECRYPT | Allow decryption.
CRYPT_EXPORT | Allow key to be exported.
CRYPT_READ | Allow parameters to be read.
CRYPT_WRITE | Allow parameters to be set.
CRYPT_MAC | Allow MACs to be used with key.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
DWORD dwMode;
BYTE pbData[16];
DWORD dwCount;
DWORD i;

// Get a handle to user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Create a random block cipher session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptGenKey!\n", GetLastError());
    goto done;
}

// Read the cipher mode.
dwCount = sizeof(DWORD);
if(!CryptGetKeyParam(hKey, KP_MODE, &dwMode, &dwCount, 0)) {
    printf("Error %x during CryptGetKeyParam!\n", GetLastError());
    goto done;
}
assert(dwCount==sizeof(BYTE));

// Print out the cipher mode.
printf("Default cipher mode: %d\n", dwMode);

// Read the initialization vector.
dwCount = 16;
if(!CryptGetKeyParam(hKey, KP_IV, pbData, &dwCount, 0)) {
    printf("Error %x during CryptGetKeyParam!\n", GetLastError());
    goto done;
}
// Print out the initialization vector.
printf("Default IV:");
for(i=0;i<dwCount;i++) printf("%2.2x ",pbData[i]);
printf("\n");

done:

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptSetKeyParam


CryptGetProvParam

The CryptGetProvParam function retrieves parameters that govern the operations of a CSP.

#include <wincrypt.h>
BOOL WINAPI CryptGetProvParam(
  HCRYPTPROV hProv, // in
  DWORD dwParam,    // in
  BYTE *pbData,     // out
  DWORD *pcbData,   // in/out
  DWORD dwFlags     // in
);

Parameters

hProv
Handle to the CSP on which to query parameters.
dwParam
Parameter number. See the "Remarks" section for a list of valid parameters.
pbData
Pointer to a buffer that receives the specified parameter data. The form of this data will vary, depending on the parameter number.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbData is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Note When one of the enumeration parameters (PP_ENUMALGS or PP_ENUMCONTAINERS) is being read, the pcbData parameter works somewhat differently. If pbData is NULL or the value pointed to by pcbData is too small, the value returned in this parameter is the size of the largest item in the enumeration list instead of the size of the item currently being read.

When one of the enumeration parameters is read and the pbData parameter is NULL, the CRYPT_FIRST flag must be specified in order for the size information to be correctly retrieved.

dwFlags
Flag values.

When one of the enumeration parameters (PP_ENUMALGS or PP_ENUMCONTAINERS) is being read, then the CRYPT_FIRST flag can be specified. When this flag is set, the first item in the enumeration list is returned. If this flag is not set, then the next item in the list is returned.

When the enumeration parameter PP_ENUMCONTAINERS is being read, then the CRYPT_MACHINE_KEYSET flag can be specified. This flag can be set if you want the enumeration to come from the HKEY_LOCAL_MACHINE portion of the registry rather than from the HKEY_CURRENT_USER portion of the registry (the default).

When the dwParam is PP_KEYSET_SEC_DESCR, the security descriptor on the registry key where the keys are stored is being retrieved. For this case, dwFlags is used to pass in the SECURITY_INFORMATION bit flags (can be combined with a bitwise OR operation), as defined in the Win32 Programmer's Reference, that indicates the requested security information. The following is specified there:

typedef DWORD SECURITY_INFORMATION;
Value | Meaning
OWNER_SECURITY_INFORMATION | Indicates the owner identifier of the object is being referenced.
GROUP_SECURITY_INFORMATION | Indicates the primary group identifier of the object is being referenced.
DACL_SECURITY_INFORMATION | Indicates the discretionary ACL of the object is being referenced.
SACL_SECURITY_INFORMATION | Indicates the system ACL of the object is being referenced.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | If the buffer specified by the pbData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
ERROR_NO_MORE_ITEMS | The end of the enumeration list has been reached. No valid data has been placed in the pbData buffer. This error is returned only when dwParam equals PP_ENUMALGS or PP_ENUMCONTAINERS.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The CSP context specified by hProv is invalid.

Remarks

The parameter number contained in the dwParam parameter can be set to one of the following values:

  • PP_CONTAINER. The key container name. When this parameter is specified, the function fills the pbData buffer with the name of the current key container. This name is in the form of a zero-terminated CHAR string.

    This string is exactly the same as the one passed in the pszContainer parameter of the CryptAcquireContext function in order to specify that the current key container be used. This parameter is often read in order to determine the name of the default key container.

  • PP_ENUMALGS. The algorithm information. When this parameter is specified, the function fills the pbData buffer with information about one of the algorithms supported by the CSP. The PP_ENUMALGS parameter must be read repeatedly to enumerate all the supported algorithms. The algorithms are not enumerated in any particular order.

    The first time that the PP_ENUMALGS parameter is read, the CRYPT_FIRST flag should be specified. This will ensure that information about the first algorithm in the enumeration list is returned. The PP_ENUMALGS parameter can then be repeatedly read in order to retrieve the information about the rest of the algorithms. When the CryptGetProvParam function fails with ERROR_NO_MORE_ITEMS, then the end of the enumeration list has been reached. A code sample illustrating this is located in the "Example" section.

    When calling CryptGetProvParam with the PP_ENUMALGS flag in the dwParam parameter the dwBits field should be changed to the length of the default key sizes.

    The following code fragment indicates the format of the data that the function returns in the pbData buffer:

    ALG_ID aiAlgid;
DWORD dwBits;
DWORD dwNameLen;
CHAR szName[dwNameLen];

    The following table defines each of these fields.

Field | Description
aiAlgid | The algorithm identifier. This is the value that is passed to the CryptGenKey, CryptDeriveKey, or CryptCreateHash functions in order to specify that a particular algorithm be used.
dwBits | The number of bits in the keys used by the algorithm. If this is a hash algorithm, this value indicates the number of bits in the hash values generated by this algorithm.
dwNameLen | The number of characters in the algorithm name, including the terminating zero.
szName | The zero-terminated name of the algorithm.

  • PP_ENUMCONTAINERS. The key container names. When this parameter is specified, the function fills the pbData buffer with the name of one of the key containers maintained by the CSP. This name is in the form of a zero-terminated CHAR string. The PP_ENUMCONTAINERS parameter must be read repeatedly to enumerate all the container names.

    These container names are enumerated in the same way as are the CSP's supported algorithms. Refer to the PP_ENUMALGS entry for more information.

  • PP_IMPTYPE. The CSP implementation type. The pbData buffer will contain a DWORD value that indicates how the CSP is implemented. Possible values are:
    • CRYPT_IMPL_HARDWARE
    • CRYPT_IMPL_SOFTWARE
    • CRYPT_IMPL_MIXED
    • CRYPT_IMPL_UNKNOWN
  • PP_NAME. The CSP name. When this parameter is specified, the function fills the pbData buffer with the name of the CSP. This name is in the form of a zero-terminated CHAR string.

    This string is identical to the one passed in the pszProvider parameter of the CryptAcquireContext function in order to specify that the current CSP be used. For example, the Microsoft Base Cryptographic Provider will return "Microsoft Base Cryptographic Provider v1.0" when this parameter is read.

  • PP_VERSION. The CSP version number. The pbData buffer will contain a DWORD value that indicates the version number of the CSP. The least significant byte contains the minor version number and the next most significant byte the major version number. For example, version 1.0 would be represented here as 0x00000100.

Version Information for
The Microsoft Base Cryptographic Provider and
The Microsoft Enhanced Cryptographic Provider:

To maintain backward compatibility with earlier versions of these providers, the name retains the "v1.0" designation in later versions. This can be seen in the wincrypt.h header file. Version 2.0 of this provider is currently shipping. To see which version of the provider you have, make a call to CryptGetProvParam with the dwParam argument set to PP_VERSION. For example, if 0x00000200 is returned in pbData, then you have version 2.0.

  • PP_KEYSET_SEC_DESCR. Indicates that the security descriptor is to be retrieved for the registry entry where the key set is stored.

    Note The PP_KEYSET_SEC_DESCR flag is not supported under Microsoft® Windows® 95.

The dwFlags parameter is used to pass in the SECURITY_INFORMATION bit flags that indicate the requested security information. The pointer to the security descriptor is returned in the pbData parameter and the length of the security descriptor is returned in the pcbData parameter. It may be helpful to look at the documentation on RegGetKeySecurity and RegSetKeySecurity (WIN32 calls).

Algorithm Identifiers

When enumerating algorithms (dwParam == PP_ENUMALGS), your application may need to determine the class of a particular algorithm. For example, you may want to display a list of encryption algorithms to the user and disregard the rest. This can be done with the GET_ALG_CLASS(x) macro. This macro takes an algorithm identifier as an argument and returns a code indicating the general class of algorithm that the identifier belongs to. Possible return values include:

  • ALG_CLASS_DATA_ENCRYPT
  • ALG_CLASS_HASH
  • ALG_CLASS_KEY_EXCHANGE
  • ALG_CLASS_SIGNATURE

The following table lists the algorithms supported by the Microsoft Base Cryptographic Provider along with the class of each algorithm.

Name | Identifier | Class
"MD2" | CALG_MD2 | ALG_CLASS_HASH
"MD5" | CALG_MD5 | ALG_CLASS_HASH
"SHA" | CALG_SHA | ALG_CLASS_HASH
"MAC" | CALG_MAC | ALG_CLASS_HASH
"RSA_SIGN" | CALG_RSA_SIGN | ALG_CLASS_SIGNATURE
"RSA_KEYX" | CALG_RSA_KEYX | ALG_CLASS_KEY_EXCHANGE
"RC2" | CALG_RC2 | ALG_CLASS_DATA_ENCRYPT
"RC4" | CALG_RC4 | ALG_CLASS_DATA_ENCRYPT

If your application does not recognize an algorithm identifier, it is not recommended that you use the algorithm. Making use of an unknown cryptographic algorithm can sometimes produce unpredictable results.

Example

This example shows how the list of algorithms supported by a particular CSP is accessed by an application:

HCRYPTPROV hProv;         // Handle to CSP
DWORD dwAlgCount;
BYTE *ptr = NULL;
DWORD i;
ALG_ID aiAlgid;
DWORD dwBits;
DWORD dwNameLen;
CHAR szName[100];         // Often allocated dynamically
BYTE pbData[1000];        // Often allocated dynamically
DWORD cbData;
DWORD dwFlags;
CHAR *pszAlgType = NULL;

// Enumerate the supported algorithms.
for(i=0 ; ; i++) {
    // Set the CRYPT_FIRST flag the first time through the loop.
    if(i == 0) {
        dwFlags = CRYPT_FIRST;
    } else {
        dwFlags = 0;
    }

// Retrieve information about an algorithm.
    cbData = 1000;
    if(!CryptGetProvParam(hProv, PP_ENUMALGS, pbData, &cbData, dwFlags)) {
        if(GetLastError() == ERROR_NO_MORE_ITEMS) {
            // Exit the loop.
            break;
        } else {
            printf("Error %x reading algorithm!\n", GetLastError());
            return;
        }
    }

    // Extract algorithm information from the 'pbData' buffer.
    ptr = pbData;
    aiAlgid = *(ALG_ID *)ptr;
    ptr += sizeof(ALG_ID);
    dwBits = *(DWORD *)ptr;
    ptr += sizeof(DWORD);
    dwNameLen = *(DWORD *)ptr;
    ptr += sizeof(DWORD);
    strncpy(szName, ptr, dwNameLen);

    // Determine the algorithm type.
    switch(GET_ALG_CLASS(aiAlgid)) {
        case ALG_CLASS_DATA_ENCRYPT: pszAlgType = "Encrypt  ";
                                     break;
        case ALG_CLASS_HASH:         pszAlgType = "Hash     ";
                                     break;
        case ALG_CLASS_KEY_EXCHANGE: pszAlgType = "Exchange ";
                                     break;
        case ALG_CLASS_SIGNATURE:    pszAlgType = "Signature";
                                     break;
        default:                     pszAlgType = "Unknown  ";
    }

    // Print information about the algorithm.
    printf("Algid:%8.8xh, Bits:%-4d, Type:%s, NameLen:%-2d, Name:%s\n",
        aiAlgid, dwBits, pszAlgType, dwNameLen, szName
    );
}

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptCreateHash, CryptDeriveKey, CryptGenKey, CryptGetKeyParam, CryptSetProvParam


CryptGetUserKey

The CryptGetUserKey function retrieves a handle to a permanent user key pair, such as the user's signature key pair.

#include <wincrypt.h>
BOOL WINAPI CryptGetUserKey(
  HCRYPTPROV hProv,      // in
  DWORD dwKeySpec,       // in
  HCRYPTKEY *phUserKey   // out
);

Parameters

hProv
A handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
dwKeySpec
The specification of the key to retrieve. The following keys are retrievable from almost all providers:
  • AT_KEYEXCHANGE. Exchange key pair.
  • AT_SIGNATURE. Signature key pair.

Additionally, some providers allow access to other user-specific keys through this function. See the documentation on the specific provider for details.

phUserKey
The address that the function copies the handle of the retrieved key to.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_KEY | The dwKeySpec parameter contains an invalid value.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_NO_KEY | The key requested by the dwKeySpec parameter does not exist.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTKEY hSignKey = 0;
HCRYPTKEY hXchgKey = 0;

// Get a handle to the user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Get a handle to the signature key.
if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hSignKey)) {
    printf("Error %x during CryptGetUserKey!\n", GetLastError());
    goto done;
}

// Get a handle to the key exchange key.
if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) {
    printf("Error %x during CryptGetUserKey!\n", GetLastError());
    goto done;
}

// Use the  'hSignKey' to verify a signature, or use 'hXchgKey' to export a key to yourself.
...

done:

// Destroy the signature key handle.
if(hSignKey != 0) CryptDestroyKey(hSignKey);

// Destroy the key exchange key handle.
if(hXchgKey != 0) CryptDestroyKey(hXchgKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

Another example is located in Encryption Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptDestroyKey, CryptGenKey


CryptHashData

The CryptHashData function is used by applications to feed data to a specified hash object. This function and CryptHashSessionKey can be called multiple times to compute the hash on long streams or on discontinuous streams.

Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object.

#include <wincrypt.h>
BOOL WINAPI CryptHashData(
  HCRYPTHASH hHash,  // in
  BYTE *pbData,      // in
  DWORD cbData,      // in
  DWORD dwFlags      // in
);

Parameters

hHash
A handle to the hash object. An application obtains this handle by using the CryptCreateHash function.
pbData
The address of the data to be hashed.
cbData
The number of bytes of data to be hashed. This must be zero if the CRYPT_USERDATA flag is set.
dwFlags
The flag values. The following values are currently defined:
  • CRYPT_USERDATA. When this flag is set, the CSP will prompt the user to input some data directly. This is then added to the hash. The application is not allowed access to the data. For example, this flag can be used to allow the user to enter a PIN into the system.

The Microsoft Base Cryptographic Provider ignores this parameter.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_BAD_KEY | A keyed hash algorithm is being used, but the session key is no longer valid. This error will be generated if the session key is destroyed before the hashing operation is complete.
NTE_BAD_LEN | The CRYPT_USERDATA flag is set and the cbData parameter has a nonzero value.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot be found.
NTE_FAIL | The function failed in some unexpected way.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Example

See CryptGetHashParam.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptHashSessionKey, CryptSignHash


CryptHashSessionKey

The CryptHashSessionKey function is used to compute the cryptographic hash on a key object. This function can be called multiple times with the same hash handle to compute the hash on multiple keys. Calls to CryptHashSessionKey can be interspersed with calls to CryptHashData.

Before calling this function the CryptCreateHash function must be called to get a handle to a hash object.

#include <wincrypt.h>
BOOL WINAPI CryptHashSessionKey(
  HCRYPTHASH hHash,  // in
  HCRYPTKEY hKey,    // in
  DWORD dwFlags      // in
);

Parameters

hHash
A handle to the hash object. An application obtains this handle by using the CryptCreateHash function.
hKey
A handle to the key object to be hashed.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_BAD_KEY | A keyed hash algorithm is being used, but the session key is no longer valid. This error will be generated if the session key is destroyed before the hashing operation is complete.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot be found.
NTE_FAIL | The function failed in some unexpected way.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
HCRYPTKEY hKey   = 0;

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
    printf("Error %x during CryptBeginHash!\n", GetLastError());
    goto done;
}

// Create a random session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptGenKey!\n", GetLastError());
    goto done;
}

// Compute the cryptographic hash on the key object.
if(!CryptHashSessionKey(hHash, hKey, 0)) {
    printf("Error %x during CryptHashSessionKey!\n", GetLastError());
    goto done;
}

// Use the hash of the key object. For instance, additional
// data could be hashed and sent in a message to several recipients.
// The recipients will be able to verify who the message originator
// is if the key used is also exported to them..
...

done:

// Destroy the hash object.
if(hHash) CryptDestroyHash(hHash);

// Destroy the session key.
if(hKey) CryptDestroyKey(hKey);

// Release the CSP handle.
if(hProv) CryptReleaseContext(hProv,0);

Another example is located in Sender Code Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptGenKey, CryptHashData


CryptImportKey

The CryptImportKey function is used to transfer a cryptographic key from a key blob to the CSP.

#include <wincrypt.h>
BOOL WINAPI CryptImportKey(
  HCRYPTPROV hProv,  // in
  BYTE *pbData,      // in
  DWORD dwDataLen,      // in
  HCRYPTKEY hPubKey, // in
  DWORD dwFlags,     // in
  HCRYPTKEY *phKey   // out
);

Parameters

hProv
A handle to the application's CSP. An application obtains this handle by using the CryptAcquireContext function.
pbData
The buffer containing the key blob. This key blob was generated by the CryptExportKey function, either by this same application or by another application running on a different computer.

This key blob consists of a standard header followed by the encrypted key.

dwDataLen
The length, in bytes, of the key blob.
hPubKey
The meaning of this parameter differs, depending on the CSP type and the type of key blob being imported.

If a signed key blob is being imported, this key is used to validate the signature of the key blob. In this case, this parameter should contain a handle to the key exchange public key of the party that created the key blob.

If the key blob is encrypted with the key exchange key pair (for example, a SIMPLEBLOB), then this parameter may be the handle to the key exchange key.

If the key blob is encrypted with a session key (for example, an encrypted PRIVATEKEYBLOB), then this parameter should contain a handle to this session key.

If the key blob is not encrypted (for example, a PUBLICKEYBLOB), then this parameter is not used, and should be zero.

dwFlags
The flag values. This parameter is currently used only when a public/private key pair is being imported into the CSP (in the form of a PRIVATEKEYBLOB). In this case, if the key being imported is eventually to be re-exported, then the CRYPT_EXPORTABLE flag must be placed in this parameter. If this flag is not used then calls to CryptExportKey with the key handle will fail.

CRYPT_NO_SALT. Specifies that a no-salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft Cryptographic Providers— Release Notes.

phKey
The address to which the function copies a handle to the key that was imported.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_ALGID | The simple key blob you are trying to import is not encrypted with the expected key exchange algorithm.
NTE_BAD_DATA | Either the algorithm that works with the public key you are trying to import is not supported by this CSP, or an attempt was made to import a session key that was encrypted with something other than one of YOUR public keys.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_TYPE | The key blob type is not supported by this CSP and is possibly invalid.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_BAD_VER | The key blob's version number does not match the CSP version. This usually indicates that the CSP needs to be upgraded.

Example

#include <wincrypt.h>

FILE *hSourceFile = NULL;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
BYTE *pbKeyBlob = NULL;
DWORD dwBlobLen;

// Open the file, getting the file handle 'hSourceFile'.
...

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Read the key blob length from the file and allocate memory.
fread(&dwBlobLen, sizeof(DWORD), 1, hSourceFile);
pbKeyBlob = malloc(dwBlobLen);

// Read the key blob from the file.
fread(pbKeyBlob, 1, dwBlobLen, hSourceFile);

// Import the key blob into the CSP.
if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey)) {
    printf("Error %x during CryptImportKey!\n", GetLastError());
    free(pbKeyBlob);
    goto done;
}

// Free memory.
free(pbKeyBlob);

// Use 'hKey' to perform cryptographic operations.
...

done:

// Destroy the session key.
if(hKey) CryptDestroyKey(hKey);

// Release the provider handle.
if(hProv) CryptReleaseContext(hProv, 0);

Another example is located in Sender Code Example.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptDestroyKey, CryptExportKey


CryptProtectData

[This is preliminary documentation and subject to change.]

CryptProtectData performs encryption on the data in a DATA_BLOB. Typically, only a user with the same login credential as the encrypter can decrypt the data. In addition, the encryption and decryption normally must be done on the same computer. See "Remarks" for information about exceptions.

BOOL WINAPI CryptProtectData(
  DATA_BLOB *DataIn,                        // in
  LPCWSTR szDataDescr,                      // in
  DATA_BLOB *pOptionalEntropy,              // in optional
  PVOID *pvReserved,                        // reserved
  CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, // in optional
  DWORD dwFlags                             // in
  DATA_BLOB *pDataOut;                      // out
);

Parameters

DataIn
Pointer to a DATA_BLOB that holds the cleartext to be encrypted.
szDataDescr
String with a readable description of the data to be encrypted. This description is included with the encrypted data. This parameter may be set to NULL.
pOptionalEntropy
Any additional entropy to be added to the encryption process. This might be a password set by the user. Any pOptionalEntropy used in the encryption phase must also be used in the decryption phase. This parameter may be set to NULL for no additional entropy.
pvReserved
Currently not used. Must be set to NULL.
pPromptStruct
Pointer to a data structure that provides information about where and when prompts are to be displayed and what the content of those prompts will be. The parameter is optional and may be set to NULL in both the encryption and decryption phases.
dwFlags
The following dwFlags are defined:
CRYPTPROTECT_LOCAL_MACHINE
When this flag is set, it associates the data encrypted with the current computer instead of with an individual user. Any user on the computer on which CryptProtectData was called can use CryptUnprotectData to decrypt the data.
CRYPTPROTECT_UI_FORBIDDEN
This flag is used for remote situations where the user interface (UI) is not an option. When this flag is set and UI is specified for either the protect or unprotect operation, the operation fails and GetLastError returns ERROR_PASSWORD_RESTRICTION.
pDataOut
Pointer to a DATA_BLOB where the function stores the encrypted data. .

Return Values

The function returns TRUE if the function succeeded, FALSE if it failed. GetLastError returns the code for the cause of any failure. The pbData of the DATA_BLOB allocated must be freed using LocalFree.

Remarks

Typically, only a user with login credentials matching those of the encrypter can decrypt the data. In addition, decryption normally can only be done on the computer where the data was encrypted. However, a user with a roaming profile may decrypt the data from another computer on the network.

If the CRYPTPROTECT_LOCAL_MACHINE dwFlag is set when the data is encrypted, any user on the machine where the encryption was done can decrypt the data.

The function creates a session key to perform the encryption. The session key is re-derived when the data is to be decrypted.

The function also adds a MAC (keyed integrity check) to the encrypted data to guard against data tampering.

France currently forbids this kind of encryption by law. In France, the Crypto API encryption call fails. The data protection function will ensure the integrity of the data but will not encrypt it.

Example

// Encrypt data from DATA_BLOB Datain to DATA_BLOB DataOut.
// Then Decrypt to DATA_BLOB DataVerify.
// Declare and initialize variables
DATA_BLOB DataIn, DataOut, DataVerify;
BYTE *pbDataInput =(BYTE *)"Hello world of data protection.";
DWORD cbDataInput = strlen(pbDataInput)+1;
DataIn.pbData = pbDataInput;
DataIn.cbData = cbDataInput;
printf("the data to be encrypted is--- %s\n",pbDataInput);

CRYPTPROTECT_PROMPTSTRUCT PromptStruct;
ZeroMemory(&PromptStruct, sizeof(PromptStruct));
PromptStruct.cbSize = sizeof(PromptStruct);
PromptStruct.szPrompt = L"This is a user prompt.";
PromptStruct.dwPromptFlags = CRYPTPROTECT_PROMPT_ON_PROTECT;

printf("Begin protect phase\n");
if(!CryptProtectData(
        &DataIn,
        L"This is the description string.", // A description sting.
        NULL,                // Optional entropy not used
        NULL,                // Reserved
        &PromptStruct,       // Pass a promptstruct
        0,
        &DataOut)){
    // The function failed. Report the error.
    printf("Encryption error! errorcode=%lu \n",GetLastError());
    return ;
    }
printf("Begin Unprotect phase\n");
LPWSTR pDescrOut = (LPWSTR)0xbaadf00d ; // NULL;
if (!CryptUnprotectData(
        &DataOut,
        &pDescrOut,
        NULL,                 // Optional Entropy,
        NULL,                 // Reserved
        &PromptStruct,        // optional promptstruct
        0,
        &DataVerify)){
    //  The function faild. Report the error.
    printf("Decryption error! errorcode=%lu\n", GetLastError());
    return;
    }
printf("The decrypted data is--%s\n", DataVerify.pbData);
printf("The description of the data was -- %s\n",pDescrOut);
LocalFree(pDescrOut);
// At this point, memcmp() could be used to compare DataIn.pbData and
// DataVerify.pbDate for equality. If the two functions worked
// correctly, the two byte strings should be identical.
LocalFree(DataOut.pbData);
LocalFree(DataVerify.pbData);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptUnprotectData


CryptQueryObject

[This is preliminary documentation and subject to change.]

The CryptQueryObject function takes a CERT_BLOB or a file name and returns the information about the content of the blob or the file.

#include <wincrypt.h>
BOOL WINAPI CryptQueryObject(
  DWORD dwObjectType,                // in
  const void *pvObject,              // in
  DWORD dwExpectedContentTypeFlags,  // in
  DWORD dwExpectedFormatTypeFlags,   // in
  DWORD dwFlags,                     // in
  DWORD *pdwMsgAndCertEncodingType,  // out
  DWORD *pdwContentType,             // out
  DWORD *pdwFormatType,              // out
  HCERTSTORE *phCertStore,           // out
  HCRYPTMSG *phMsg,                  // out
  const void **ppvContext            // out
);

Parameters

dwObjectType
Indicates the type of the pvObject. It should be one of the following:
ObjectType | Description
CERT_QUERY_OBJECT_FILE | Get the information about a file
CERT_QUERY_OBJECT_BLOB | Get the information about a blob

If the dwObjectType is not correct for the object, program behavior is unspecified.

pvObject
Pointer to the object to be queried.

If dwObjectType is CERT_QUERY_OBJECT_FILE, pvObject is a LPWSTR. If dwObjectType is CERT_QUERY_OBJECT_BLOB, pvObject is a PCERT_BLOB.

If the pvObject does not point to the correct type specified by dwObjectType, program behavior is unspecified.

dwExpectedContentTypeFlags
Indicates the expected content type. Can be one of the following:
Expected Content Type Flag Name | Content type
CERT_QUERY_CONTENT_FLAG_ALL | any type
CERT_QUERY_CONTENT_FLAG_CERT | single certificate
CERT_QUERY_CONTENT_FLAG_CTL | single CTL
CERT_QUERY_CONTENT_FLAG_CRL | single CRL
CERT_QUERY_CONTENT_FLAG_
SERIALIZED_STORE 		serialized store
CERT_QUERY_CONTENT_FLAG_
SERIALIZED_CERT 		serialized single
certificate
CERT_QUERY_CONTENT_FLAG_
SERIALIZED_CTL 		serialized single CTL
CERT_QUERY_CONTENT_FLAG_
SERIALIZED_CRL 		serialized single CRL
CERT_QUERY_CONTENT_FLAG_
PKCS7_SIGNED 		PKCS#7 signed
message
CERT_QUERY_CONTENT_FLAG_
PKCS7_UNSIGNED 		PKCS#7 unsigned
message
CERT_QUERY_CONTENT_FLAG_
PKCS7_SIGNED_EMBED 		embedded PKCS7
signed message
CERT_QUERY_CONTENT_FLAG_PKCS10 | PKCS#10
CERT_QUERY_CONTENT_FLAG_PFX | PFX BLOB

If the dwExpectedContentTypeFlags is not correct for the type specified by pdwContentType, the function will return a FALSE.

dwExpectedFormatTypeFlags
Indicates the expected format type. Can be one of the following:
Expected Format Type Flags Name | Format type
CERT_QUERY_FORMAT_FLAG_ALL | any format
CERT_QUERY_FORMAT_FLAG_BINARY | binary format
CERT_QUERY_FORMAT_FLAG_BASE64_
ENCODED 		base64 encoded

If the dwExpectedFormatTypeFlags is not correct for the type specified by pdwFormatType, the function will return a FALSE.

dwFlags
Flag values. This parameter is reserved for future use and should always be set to 0.
pdwMsgAndCertEncodingType
Pointer to the type of encoding used in the message. If no output is wanted, set pdwMsgAndCertEncodingType to NULL. The returned encoding type will be any combination of the following:
Encoding Type | value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pdwContentType
Pointer to the returned encoding type of the content. If no output is wanted, set pdwContentType to NULL. The returned encoding type may be any one of the following:
Content Type | value
CERT_QUERY_CONTENT_CERT | 1
CERT_QUERY_CONTENT_CTL | 2
CERT_QUERY_CONTENT_CRL | 3
CERT_QUERY_CONTENT_SERIALIZED_STORE | 4
CERT_QUERY_CONTENT_SERIALIZED_CERT | 5
CERT_QUERY_CONTENT_SERIALIZED_CTL | 6
CERT_QUERY_CONTENT_SERIALIZED_CRL | 7
CERT_QUERY_CONTENT_PKCS7_SIGNED | 8
CERT_QUERY_CONTENT_PKCS7_UNSIGNED | 9
CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED | 10
CERT_QUERY_CONTENT_PKCS10 | 11
CERT_QUERY_CONTENT_PFX | 12

pdwFormatType
Pointer to the returned format type of the content. If no output is wanted, set pdwFormatType to NULL. The returned format type may be any one of the following:
Format Type | value
CERT_QUERY_FORMAT_BINARY | 1
CERT_QUERY_FORMAT_BASE64_ENCODED | 2

phCertStore
*phCertStore is a NULL unless dwContentType is one of the content types in the following table. If dwContentType is one of these content types, phCertStore is a pointer to a handle to a certificate store that includes all of the certificates, CRLs, and CTLs in the object.

The caller should free *phCertStore via CertCloseStore.

If no output is wanted, set phCertStore to NULL.
Content Type | value
CERT_QUERY_CONTENT_CERT | 1
CERT_QUERY_CONTENT_CTL | 2
CERT_QUERY_CONTENT_CRL | 3
CERT_QUERY_CONTENT_SERIALIZED_STORE | 4
CERT_QUERY_CONTENT_SERIALIZED_CERT | 5
CERT_QUERY_CONTENT_SERIALIZED_CTL | 6
CERT_QUERY_CONTENT_SERIALIZED_CRL | 7
CERT_QUERY_CONTENT_PKCS7_SIGNED | 8
CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED | 10

phMsg
*phMsg is a NULL unless dwContentType is one of the content types in the following table. If dwContentType is one of these content types, phMsg is a pointer to a handle to an opened message.

The caller should free *phMsg via CryptMsgClose.

If no output is wanted, set phMsg to NULL.
dwContentType | value
CERT_QUERY_CONTENT_PKCS7_SIGNED | 8
CERT_QUERY_CONTENT_PKCS7_UNSIGNED | 9
CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED | 10

ppvContext
Pointer to the context pointer. The context is dependent upon dwContentType. The following table contains the types contained at pvContext. The caller should free the pvContext via the function shown in the table.
If no output is wanted, set ppvContext to NULL.
pvContext dwContentType free pvContext via
PCCERT_
CONTEXT 		CERT_QUERY_
CONTENT_CERT 		CertFreeCertificate
Context
PCCERT_
CONTEXT 		CERT_QUERY_
CONTENT_
SERIALIZED_CERT 		CertFreeCertificate
Context
PCCTL_
CONTEXT 		CERT_QUERY_
CONTENT_CTL 		CertFreeCTLContext
PCCTL_
CONTEXT 		CERT_QUERY_
CONTENT_
SERIALIZED_CTL 		CertFreeCTLContext
PCCRL_
CONTEXT 		CERT_QUERY_
CONTENT_CRL 		CertFreeCRLContext
PCCRL_
CONTEXT 		CERT_QUERY_
CONTENT_
SERIALIZED_CRL 		CertFreeCRLContext

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Example

// EXAMPLE CODE FOR USING CryptQueryObject().
// Assume that a pointer to the CERT_BLOB
// (pvObject) is already known.

// Set up the variables.
DWORD dwObjectType;               // Type of the object
const CERT_BLOB *pvObject;        // Pointer to a CERT_BLOB-
                                  //   initialized elsewhere
DWORD dwExpectedContentTypeFlags; // Content type
DWORD dwExpectedFormatTypeFlags;  // Format flags
DWORD dwFlags;                    // Flag value- set to 0
DWORD dwMsgAndCertEncodingType;
DWORD dwContentType;
DWORD dwFormatType;
HCERTSTORE hCertStore;
HCRYPTMSG hMsg;
const void *pvContext;            // Using PCCERT_CONTEXT because
                                  //   this is expecting a content
                                  //   type of CERT_QUERY_CONTENT_CERT
BOOL fResult;                     // Return value- True if function
                                  //   successful False if function
                                  //   fails

// Function call to CryptQueryObject
fResult= CryptQueryObject(
           CERT_QUERY_OBJECT_BLOB,// in- object type- open a blob
           pvObject,              // in- object- because dwObjectType
                                  //   is a blob, this is a pointer to
                                  //   a blob- initialized elsewhere
           CERT_QUERY_CONTENT_FLAG_CERT,
                                  // in- content flag- single
                                  //   certificate
           CERT_QUERY_FORMAT_BINARY, // in- format flag- binary format
           0,                        // in- dwFlags set to 0
           &dwMsgAndCertEncodingType,// out, optional
           &dwContentType,           // out, optional- this example
                                     //   should be
                                     //   CERT_QUERY_CONTENT_CERT
           &dwFormatType,            // out, optional
           &hCertStore,              // out, optional
           &hMsg,                    // out, optional- in this example
                                     //   output will be a NULL
           &pvContext);              // out, optional

cout<< "CryptQueryObject;"<< endl
    << "fResult = "<< fResult<< endl<< endl;
if (fResult) {              // returned value is TRUE
                            //   CryptQueryObject is successful
    cout<< "the encoding type (dwMsgAndCertEncodingType) is "
        << dwMsgAndCertEncodingType<< endl
        << "the content type (dwContentType) is "<< dwContentType
        << endl
        << "the format type (dwFormatType) is "<< dwFormatType<< endl
        << "the certificate store (hCertStore) is at "<< hCertStore
        << endl
        << "the message (hMsg) is "<< hMsg<< endl
        << "the context (pvContext) is "<< pvContext<< " bytes "
        << endl;
    }

else {                      // returned value is FALSE
     cout<< "CryptQueryObject failed" << endl
         << "error code = "<< GetLastError()<< endl;
}
CryptMsgClose(              // free memory
     hMsg);
CertCloseStore(             // free memory
     hCertStore,
     CERT_CLOSE_STORE_FORCE_FLAG);
CertFreeCertificateContext( // free memory
     (PCCERT_CONTEXT)pvContext);
                            // PCCERT_CONTEXT because this is a
                            //  CERT_QUERY_CONTENT_CERT

QuickInfo

Windows NT: Requires version 4.0 SP3 or later (or version 4.0 with IE 3.02 or later).
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptReleaseContext

The CryptReleaseContext function is used to release a handle to a CSP and a key container.

This should be performed when the application is finished using the CSP. After this function is called, the CSP handle specified by the hProv parameter will no longer be valid. Neither the key container nor any key pairs are destroyed by this function.

#include <wincrypt.h>
BOOL WINAPI CryptReleaseContext(
  HCRYPTPROV hProv,  // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to the application's CSP. This is the handle the application obtains by using the CryptAcquireContext function.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, then the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_BUSY | The CSP context specified by hProv is currently being used by another process.
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.

Remarks

After this function has been called, the session is over, and all existing session keys and hash objects that were created by using the hProv handle become invalid. In practice, all of these objects should be destroyed (with the CryptDestroyKey and CryptDestroyHash functions) before the CryptReleaseContext function is called.

Example

See CryptHashSessionKey.

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptDestroyKey, CryptDestroyHash


CryptSetHashParam

The CryptSetHashParam function, in theory, customizes the operations of a hash object. Currently, only a single parameter is defined for this function.

#include <wincrypt.h>
BOOL WINAPI CryptSetHashParam(
  HCRYPTHASH hHash,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // in
  DWORD dwFlags      // in
);

Parameters

hHash
Handle to the hash object on which to set parameters.
dwParam
Parameter number. See the "Remarks" section for a list of valid parameters.
pbData
Parameter data buffer. Place the parameter data in this buffer before calling CryptSetHashParam. The form of this data will vary, depending on the parameter number.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_BUSY | The CSP context is currently being used by another process.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero or the pbData buffer contains an invalid value.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot be found.
NTE_FAIL | The function failed in some unexpected way.

Remarks

The dwParam parameter can be set to one of the following values:

  • HP_HMAC_INFO. The pbData buffer should contain a pointer to an HMAC_INFO structure that specifies the cryptographic hash algorithm and the inner and outer strings to be used.
  • HP_HASHVAL. Hash value. The pbData buffer should contain a byte array containing a hash value to place directly into the hash object. Before setting this parameter, the size of the hash value should be determined by reading the HP_HASHSIZE parameter with the CryptGetHashParam function.

    Some CSPs will not support this capability. Occasionally, it is convenient to sign a hash value that has been generated elsewhere. This is the usual sequence of operations:

    1. The application creates a hash object with CryptCreateHash.
    2. It specifies a hash value by setting the HP_HASHVAL parameter.
    3. It signs the hash value by using CryptSignHash, obtaining a digital signature block.
    4. It destroys the hash object by using CryptDestroyHash.

Note Some CSP types may add additional parameters that can be set with this function.

Example

// EXAMPLE CODE FOR USING CryptSetHashParam
// Set up the variables.
HCRYPTHASH     hHash;      // A handle to the hash object on which to set
                        // parameters
DWORD       dwParam;    // dwParam- paramater # can be HP_HMAC_INFO-
                        // initialized elsewhere
BYTE        pbData[16]; // The parameter data buffer
DWORD       dwFlags = 0;// set to zero
BOOL        Return;
Return = CryptSetHashParam(hHash, dwParam, pbData, dwFlags);
if (Return) {
 cout<< "function succeeds"<< endl;
}
else {
 cout<< "retrieve error"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptCreateHash, CryptDestroyHash, CryptGetHashParam, CryptSetKeyParam, CryptSignHash


CryptSetKeyParam

The CryptSetKeyParam function customizes various aspects of a key's operations.

Generally, this function is used to set session-specific parameters on symmetric keys.

The Microsoft Base Cryptographic Provider has no parameters that can be set on key exchange or signature keys. However, custom providers may define parameters that can be set on these keys.

#include <wincrypt.h>
BOOL WINAPI CryptSetKeyParam(
  HCRYPTKEY hKey, // in
  DWORD dwParam,  // in
  BYTE *pbData,   // in
  DWORD dwFlags   // in
);

Parameters

hKey
Handle to the key on which to set parameters.
dwParam
The parameter number. See the "Remarks" section for a list of valid parameters.
pbData
The parameter data buffer. Place the parameter data in this buffer before calling CryptSetKeyParam. The form of this data will vary, depending on the parameter number.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_BUSY | The CSP context is currently being used by another process.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero or the pbData buffer contains an invalid value.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot be found.
NTE_FAIL | The function failed in some unexpected way.
NTE_FIXEDPARAMETERS | Some CSPs will have hard coded P, Q, and G values. If this is the case, then using the KP_P, KP_Q, and KP_G for the value of dwParam will cause this error.

Remarks

For all session key types, the dwParam value can be set to one of the following key parameter types.

Parameter type | Description
KP_SALT | The salt value. The pbData buffer should contain a BYTE array specifying a new salt value. This value is made part of the session key. The size of the salt value will vary depending on the CSP being used, so before setting this parameter, it should be read by using CryptGetKeyParam in order to determine its size. When you suspect that the base data used for derived keys is less than ideal, salt values are often used to make the session keys more unique. This makes dictionary attacks more difficult. When using the Microsoft Base Cryptographic Provider, this parameter defaults to zero.
KP_SALT_EX | To set a salt value, a user can call the CryptSetKeyParam function with the KP_SALT_EX parameter value specified and with the pbData parameter pointing to a CRYPTOAPI_BLOB structure containing the salt. For more information, see Specifying a Salt Value.
KP_PERMISSIONS | The key permissions flags. The pbData buffer should contain a DWORD value specifying zero or more permission flags. Refer to the CryptGetKeyParam function for a description of these flags. When using the Microsoft Base Cryptographic Provider, this parameter defaults to 0xFFFFFFFF.

If a DSS key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

Parameter type | Description
KP_P | The pbData buffer should contain a pointer to the prime modulus P from the DSS key blob that is to be set. The data is in the form of a BLOB Structure where the pbData member is the value and the cbData member is the length of the value. The value is expected with no header information and in little endian form.
KP_Q | The pbData buffer should contain a pointer to the prime Q from the DSS key blob that is to be set. The data is in the form of a BLOB Structure where the pbData member is the value and the cbData member is the length of the value. The value is expected with no header information and in little endian form.
KP_G | The pbData buffer should contain a pointer to the generator G from the DSS key blob that is to be set The data is in the form of a BLOB Structure, where the pbData member is the value and the cbData member is the length of the value. The value is expected with no header information and in little endian form.
KP_X | Once the P, Q, and G values have been set, a call can be made to CryptSetKeyParam specifying the KP_X value for dwParam and NULL for the pbData parameter. This will cause the X and Y values to be generated.

If a block cipher session key is specified by hKey, the dwParam value can also be set to one of the following parameter types.

Parameter type Description
KP_EFFECTIVE_
KEYLEN 		This parameter may be used only with RC2 keys and has been added due to the previous implementation of CryptSetKeyParam in the Microsoft® Windows NT® version 4.0 Service Pack 2 MS Enhanced Provider. In that implementation the RC2 keys in the Enhanced Provider were 128 bits in strength, but the effective key length used to expand keys into the key table was only 40 bits. This reduced the strength of the algorithm to 40 bits.

To maintain backward compatibility, the previous implementation will remain as is. However, the effective key length may be set to be greater than 40 bits by using this parameter value in the CryptSetKeyParam call. The effective key length is passed in the pbData parameter as a pointer to a DWORD with the effective key length value. The minimum effective key length on the Microsoft Base Cryptographic Provider is 1 and the maximum is 40. In the MS Enhanced Provider the minimum is 1 and the maximum is 1024. The key length must be set prior to encrypting or decrypting with the key.
KP_IV The initialization vector. The pbData buffer should contain a BYTE array specifying the initialization vector. This array should contain block_length/8 elements. For example, if the block length is 64 bits, the initialization vector will consist of eight bytes.

When using the Microsoft Base Cryptographic Provider, this parameter defaults to zero.
KP_PADDING The padding mode. The pbData buffer should contain a DWORD value specifying the padding method to be used by the cipher. Following are the padding modes currently defined:

PKCS5_PADDING. PKCS 5 (sec 6.2) padding method.

When using the Microsoft Base Cryptographic Provider, this parameter defaults to PKCS5_PADDING.
KP_MODE The cipher mode. The pbData buffer should contain a DWORD value specifying the cipher mode to be used. Refer to the CryptGetKeyParam function for a list of the defined cipher modes.

When using the Microsoft Base Cryptographic Provider, this parameter defaults to CRYPT_MODE_CBC.
KP_MODE_BITS The number of bits to feed back. The pbData buffer contains a DWORD value indicating the number of bits that are processed per cycle when the OFB or CFB cipher mode is used.

When using the Microsoft Base Cryptographic Provider, this parameter defaults to eight.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
DWORD dwMode;
BYTE pbData[16];
DWORD dwCount;
DWORD i;

// Get a handle to the user default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Create a random block cipher session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) {
    printf("Error %x during CryptGenKey!\n", GetLastError());
    goto done;
}

// Set the cipher mode.
dwMode = CRYPT_MODE_ECB;
if(!CryptSetKeyParam(hKey, KP_MODE, &dwMode, 0)) {
    printf("Error %x during CryptSetKeyParam!\n", GetLastError());
    goto done;
}

// Generate a random initialization vector.
if(!CryptGenRandom(hProv, 8, pbData)) {
    printf("Error %x during CryptGenRandom!\n", GetLastError());
    goto done;
}

// Set the initialization vector.
if(!CryptSetKeyParam(hKey, KP_IV, pbData, 0)) {
    printf("Error %x during CryptSetKeyParam!\n", GetLastError());
    goto done;
}

// Use 'hKey' to encrypt a message.
...

done:

// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptGenKey, CryptGetKeyParam


CryptSetProvider

The CryptSetProvider function is used to specify the current user default CSP.

After this function has been called, any calls this user subsequently makes to CryptAcquireContext specifying the dwProvType provider type but not a provider name, will result in the pszProvName provider being used.

Note Typical applications will not use this function. It is intended for use solely by administrative applications.

#include <wincrypt.h>
BOOL WINAPI CryptSetProvider(
  LPCTSTR pszProvName,  // in
  DWORD dwProvType      // in
);

Parameters

pszProvName
The name of the new default CSP. This CSP should have already been installed on the computer.
dwProvType
The provider type of the CSP specified by the pszProvName parameter.

Return Values

If the function succeeds, the return value is TRUE. If the function fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory during the operation.
Error codes returned from the RegCreateKeyEx function. | See RegCreateKeyEx.
Error codes returned from the RegSetValueEx function. | See RegSetValueEx.

Remarks

Typical applications do not usually specify a CSP name when calling the CryptAcquireContext function. This gives the users a certain amount of freedom in that they can select a CSP that has an appropriate level of security.

This means that a call to CryptSetProvider will often determine the CSP of a given type used by all applications that run from that point on. With this being the case, the CryptSetProvider function should never be called without the user's consent.

Example

HCRYPTPROV hProv = 0;

// Specify the default PROV_RSA_SIG provider. Note that this assumes
// that a CSP with a type of PROV_RSA_SIG and named "Joe's Provider"
// has already been installed.
if(!CryptSetProvider(TEXT("Joe's Provider"), PROV_RSA_SIG)) {
    printf("Error %x during CryptSetProvider!\n", GetLastError());
    return;
}

// Get a handle to the provider that you just made the default.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_SIG, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    return;
}

...

// Release the provider handle.
if(!CryptReleaseContext(hProv, 0)) {
    printf("Error %x during CryptReleaseContext!\n", GetLastError());
    return;
}

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptAcquireContext


CryptSetProviderEx

The CryptSetProviderEx function is used to specify either the current user default CSP or the machine default CSP.

A current user default takes precedence over the machine default. If the current user default CSP is specified, then after this function has been called, any calls this user subsequently makes to CryptAcquireContext specifying the dwProvType provider type but not a provider name, will result in the pszProvName provider being used. In the case where the machine default is specified, subsequent calls to CryptAcquireContext by a user with no default CSP as described above will result in the pszProvName provider being used.

#include <wincrypt.h>
BOOL WINAPI CryptSetProviderEx(
  LPCTSTR pszProvName, // in
  DWORD dwProvType,    // in
  DWORD *pdwReserved,  // in
  DWORD dwFlags        // in
);

Parameters

pszProvName
The name of the new default CSP. This CSP should have already been installed on the computer.
dwProvType
The provider type of the CSP specified by the pszProvName parameter.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values.
Flag value | Description
CRYPT_MACHINE_DEFAULT | Causes the machine default CSP of the given type to be set.
CRYPT_USER_DEFAULT | Causes the user default CSP of the given type to be set.
CRYPT_DELETE_DEFAULT | Can be used in conjunction with CRYPT_MACHINE_DEFAULT or CRYPT_USER_DEFAULT to delete the default.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_NOT_ENOUGH_MEMORY | The operating system ran out of memory.

Remarks

Most applications will not specify a CSP name when calling the CryptAcquireContext function. This gives the users a certain amount of freedom in that they can select a CSP that has an appropriate level of security.

This means that calls to CryptSetProviderEx will often determine the CSP of a given type used by all applications from that point on. With this being the case, CryptSetProviderEx should never be called without the user's consent.

Example

HCRYPTPROV     hProv = 0;

// Specify the default PROV_RSA_SIG provider for the machine.  Note that this assumes that a
// CSP with a type of PROV_RSA_SIG and named "Joe's Provider" has already been installed.
if (!CryptSetProviderEx(TEXT("Joe's Provider"), PROV_RSA_SIG, NULL,
        CRYPT_MACHINE_DEFAULT))
   {printf("Error %x during CryptSetProviderEx!\n", GetLastError);
    return;
   }

// Get a handle to the provider you just made default
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_SIG, 0))
   {printf("Error %x during CryptAcquireContext!\n", GetLastError);
    return;
   }

...

// Release the provider handle.
if (!CryptReleaseContext(hProv, 0))
   {printf("Error %x during CryptReleaseContext!\n", GetLastError);
    return;
   }

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptAcquireContext, CryptSetProvider


CryptSetProvParam

The CryptSetProvParam function customizes the operations of a CSP.

#include <wincrypt.h>
BOOL WINAPI CryptSetProvParam(
  HCRYPTPROV hProv,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // in
  DWORD dwFlags      // in
);

Parameters

hProv
A handle to the CSP on which to set parameters.
dwParam
The parameter number to set. The currently defined parameter values are as follows (see "Remarks" for additional details).
Parameter | Description
PP_CLIENT_HWND | Specifies that a window handle is contained in pbData.
PP_KEYSET_SEC_DESCR | Specifies that the security descriptor on the registry entry where the stored key set is being assigned, and its value is contained in pbData.

pbData
The parameter data buffer. Place the parameter data in this buffer before calling CryptSetProvParam. The form of this data will vary, depending on the parameter number.
dwFlags
The flag values. When dwParam is PP_KEYSET_SEC_DESCR, dwFlags contains the SECURITY_INFORMATION applicable bit flags (can be combined with a bitwise OR operation), as defined in the Win32 Programmer's Reference. See CryptGetProvParam for additional details.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_BUSY | The CSP context is currently being used by another process.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero or the pbData buffer contains an invalid value.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot be found.
NTE_FAIL | The function failed in some unexpected way.

Remarks

When dwParam is set to PP_CLIENT_HWND, the pbData buffer should contain a DWORD value specifying the window handle that the provider is to use when interacting directly with the user. When setting this parameter, applications should call the CryptSetProvParam function before calling CryptAcquireContext. This is necessary because many CSPs will display a user interface during the CryptAcquireContext function. Note that CSPs that do not ever display a user interface will ignore the value of this parameter.

When setting the security descriptor, the pbData parameter holds the pointer to the security descriptor to be set. It may be helpful to look at the documentation on RegGetKeySecurity and RegSetKeySecurity (WIN32 calls).

Note The PP_KEYSET_SEC_DESCR flag is not supported under Microsoft® Windows® 95.

Example

#include <wincrypt.h>

// Set up the variables.
HCRYPTPROV hProv = 0;
HWND mainhwnd;
HINSTANCE hThisInst;
//Specify that a window handle is contained in pbData.
DWORD dwParam = PP_CLIENT_HWND;

mainhwnd = CreateWindow(
     szWinName,
     "Security Examples Program",
     WS_OVERLAPPEDWINDOW | WS_VSCROLL,
     CW_USEDEFAULT, CW_USEDEFAULT, // x,y
     700, 500,     // width,height
     HWND_DESKTOP, // parent window
     NULL,
     hThisInst,
     NULL);

BYTE * pbData = (BYTE *) mainhwnd;

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
}
// Set the PP_CLIENT_HWND parameter for the default provider.
CryptSetProvParam(hProv, dwParam, pbData, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.

See Also

CryptAcquireContext, CryptGetProvParam, CryptSetKeyParam


CryptSignHash

The CryptSignHash function is used to sign a piece of data. Because all signature algorithms are asymmetric and thus incredibly slow, the CryptoAPI will not let data be signed directly. Instead, you must first hash the data and then use CryptSignHash to sign the hash value.

#include <wincrypt.h>
BOOL WINAPI CryptSignHash(
  HCRYPTHASH hHash,     // in
  DWORD dwKeySpec,      // in
  LPCTSTR sDescription, // in
  DWORD dwFlags,        // in
  BYTE *pbSignature,    // out
  DWORD *pdwSigLen      // in/out
);

Parameters

hHash
Handle to the hash object to be signed.
dwKeySpec
Key pair to use to sign the hash. The following keys can be specified.
Value | Description
AT_KEYEXCHANGE | Exchange private key
AT_SIGNATURE | Signature private key

The signature algorithm used is specified when the key pair was originally created.

The only signature algorithm that the Microsoft Base Cryptographic Provider supports is the RSA Public-Key algorithm.

sDescription
This parameter should no longer be used, and should be set to NULL to prevent security vulnerabilities. However, it is still supported for backward compatibility in the Microsoft Base Cryptographic Provider.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.
pbSignature
Pointer to a buffer that receives the signature data.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pdwSigLen
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pdwSigLen parameter. When the function returns, the variable pointed to by the pdwSigLen parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbSignature is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
ERROR_MORE_DATA | If the buffer specified by the pbSignature parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code and stores the required buffer size, in bytes, into the variable pointed to by pdwSigLen.
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot be found.
NTE_NO_KEY | The private key specified by dwKeySpec does not exist.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Remarks

Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object. The CryptHashData or CryptHashSessionKey function is then used to add the data or session keys to the hash object.

After this function has been completed, the only hash function that can be called using the hHash handle is the CryptDestroyHash function.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
#define BUFFER_SIZE 256
BYTE pbBuffer[BUFFER_SIZE];
HCRYPTHASH hHash = 0;
BYTE *pbSignature = NULL;
DWORD dwSigLen;
LPTSTR szDescription = TEXT("Test Data");
DWORD i;

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Fill the buffer with test data.
for(i = 0 ; i < BUFFER_SIZE ; i++) {
    pbBuffer[i] = (BYTE)i;
}

// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
    printf("Error %x during CryptCreateHash!\n", GetLastError());
    goto done;
}

// Compute the cryptographic hash of the buffer.
if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
    printf("Error %x during CryptHashData!\n", GetLastError());
    goto done;
}

// Determine the size of the signature and allocate memory.
dwSigLen= 0;
if(!CryptSignHash(hHash, AT_SIGNATURE, TEXT(""), 0, NULL,
                        &dwSigLen)) {
    printf("Error %x during CryptSignHash!\n", GetLastError());
    if(GetLastError()!=NTE_BAD_LEN) goto done;
}
if((pbSignature = malloc(dwSigLen)) == NULL) {
    printf("Out of memory!\n");
    goto done;
}

// Sign the hash object.
if(!CryptSignHash(hHash, AT_SIGNATURE, szDescription, 0, pbSignature,
                        &dwSigLen)) {
    printf("Error %x during CryptSignHash!\n", GetLastError());
    goto done;
}

// Store or transmit the signature, test buffer, and description string.
...

done:

// Free memory to be used to store signature.
if(pbSignature != NULL) free(pbSignature);

// Destroy the hash object.
if(hHash != 0) CryptDestroyHash(hHash);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use advapi32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptCreateHash, CryptDestroyHash, CryptHashData, CryptHashSessionKey, CryptVerifySignature


CryptUnprotectData

[This is preliminary documentation and subject to change.]

CryptUnprotectData performs a decryption and integrity check of the data in a DATA_BLOB. Normally, only a user with the same login credential as the encrypter can decrypt the data. In addition, the encryption and decryption must be done on the same computer. See "Remarks" in CryptProtectData for information about exceptions.

BOOL WINAPI CryptUnprotectData(
  DATA_BLOB *DataIn,                         // in
  LPWSTR *ppszDataDescr,                     // out optional
  DATA_BLOB *pOptionalEntropy,               // in optional
  PVOID *pvReserved,                         // reserved
  CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,  // in optional
  DWORD dwFlags                              // in
  DATA_BLOB *pDataOut;                       // out
);

Parameters

DataIn
Pointer to a DATA_BLOB that holds the encrypted data. The DATA_BLOB's cbData member holds the length of the pbData byte string that contains the text to be encrypted.
ppszDataDescr
Pointer to an address where a readable description of the encrypted data included with the encrypted data will be placed. This parameter is optional and may be set to NULL.
pOptionalEntropy
Pointer to a string that holds a password or other additional entropy used when the data was encrypted. This parameter is optional and may be set to NULL; however, if optional entropy was used in the encryption phase, that same entropy must be used for decryption phase.
pvReserved
Currently not used. Must be set to NULL.
pPromptStruct
Pointer to a data structure that provides information about where and when prompts are displayed and what the content of those prompts will be. This parameter is optional and may be set to NULL.
dwFlags
CRYPTPROTECT_UI_FORBIDDEN is used for remote situations where the user interface (UI) is not an option. When this flag is set and UI is specified for either the protect or unprotect operation, the operation fails and GetLastError returns ERROR_PASSWORD_RESTRICTION.
pDataOut
Pointer to a DATA_BLOB where the function stores the decrypted data.

Return Values

The function returns TRUE if the function succeeded, FALSE if it failed. GetLastError returns the code for the cause of any failure. The pbData of the DATA_BLOB allocated and a non NULL ppszDataDescr must be freed using LocalFree.

Remarks

The CryptProtectData function creates a session key when the data is encrypted. That key is re-derived and used to decrypt the data blob.

The MAC hash added to the encrypted data can be used to determine whether the encrypted data was altered in any way. Any tampering results in a ERROR_INVALID_DATA return.

Example

See example using CryptProtectData.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptProtectData


CryptVerifySignature

The CryptVerifySignature function is used to verify a signature against a hash object.

Before calling this function, the CryptCreateHash function must be called to get a handle to a hash object. The CryptHashData and/or CryptHashSessionKey functions are then used to add the data and/or session keys to the hash object.

After this function has been completed, the only hash function that can be called by using the hHash handle is the CryptDestroyHash function.

#include <wincrypt.h>
BOOL WINAPI CryptVerifySignature(
  HCRYPTHASH hHash,      // in
  BYTE *pbSignature,     // in
  DWORD dwSigLen,        // in
  HCRYPTKEY hPubKey,     // in
  LPCTSTR sDescription,  // in
  DWORD dwFlags          // in
);

Parameters

hHash
A handle to the hash object to verify against.
pbSignature
The address of the signature data to be verified.
dwSigLen
The number of bytes in the pbSignature signature data.
hPubKey
A handle to the public key to use to authenticate the signature. This public key must belong to the key pair that was originally used to create the digital signature.
sDescription
This parameter should no longer be used, and should be set to NULL to prevent security vulnerabilities. However, it is still supported for backward compatibility in the Microsoft Base Cryptographic Provider.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.

Return Values

If the function succeeds, the return value is TRUE. If it fails, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function. The error codes prefaced by "NTE" are generated by the particular CSP you are using.

Error code | Description
ERROR_INVALID_HANDLE | One of the parameters specifies an invalid handle.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_FLAGS | The dwFlags parameter is nonzero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_KEY | The hPubKey parameter does not contain a handle to a valid public key.
NTE_BAD_SIGNATURE | The signature was not verified. This could be because the data itself has changed, the description string did not match, or the wrong public key was specified by hPubKey. This error can also be returned if the hashing or signature algorithms do not match the ones used to create the signature.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot be found.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Example

#include <wincrypt.h>

HCRYPTPROV hProv = 0;
#define BUFFER_SIZE 256
BYTE pbBuffer[BUFFER_SIZE];
HCRYPTHASH hHash = 0;
HCRYPTKEY hPubKey = 0;
BYTE *pbSignature = NULL;
DWORD dwSigLen;
LPTSTR szDescription = NULL;

// Get a handle to the default provider.
if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
    printf("Error %x during CryptAcquireContext!\n", GetLastError());
    goto done;
}

// Load 'pbBuffer' with 'BUFFER_SIZE' bytes of test data. This must
// be the same data that was originally signed.
...
// Point 'pbSignature' at the signature created by a previous call
// to CryptSignHash. Set 'dwSigLen' to the number of bytes in the
// signature.
...

// Point 'szDescription' at the text describing the data being
// signed. This must be the same description text that was originally
// passed to CryptSignHash.
...

// Get the public key of the user who created the digital signature
// and import it into the CSP by using CryptImportKey. This will return
// a handle to the public key in 'hPubKey'.
...

// Create a hash object.
if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
    printf("Error %x during CryptCreateHash!\n", GetLastError());
    goto done;
}

// Compute the cryptographic hash of the buffer.
if(!CryptHashData(hHash, pbBuffer, BUFFER_SIZE, 0)) {
    printf("Error %x during CryptHashData!\n", GetLastError());
    goto done;
}

// Validate the digital signature.
if(!CryptVerifySignature(hHash, pbSignature, dwSigLen, hPubKey,
                            szDescription, 0)) {
    if(GetLastError() == NTE_BAD_SIGNATURE) {
        printf("Signature not validated!\n");
    } else {
        printf("Error %x during CryptVerifySignature!\n",
                GetLastError());
    }
} else {
    printf("Signature validated\n");
}

done:
...

// Release the public key.
if(hPubKey != 0) CryptDestroyKey(hPubKey);

// Destroy the hash object.
if(hHash != 0) CryptDestroyHash(hHash);

// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);

QuickInfo

Windows NT: Requires version 4.0 or later.
Windows: Requires Windows 95 OSR2 or later (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CryptCreateHash, CryptDestroyHash, CryptHashData, CryptHashSessionKey, CryptSignHash


Certificate Store Functions

These Win32® functions help you manage the storage and retrieval of Certificates, Certificate Revocation Lists (CRLs), and Certificate Trust Lists (CTLs).

These functions are listed in the following 3 tables, which separates them into the following categories:

Common Certificate Functions

Certificate Revocation List Functions

Certificate Trust List Functions

All of the functions can be found in Wincrypt.h.


Common Certificate Functions

These Win32® functions help you to manage the storage and retrieval of certificates and manage the certificate store.

Function | Description
CertAddCertificateContextToStore | Adds a certificate context to the certificate store.
CertAddCertificateLinkToStore | Adds a link in a certificate store to a certificate context in a different store.
CertAddEncodedCertificateToStore | Converts the encoded certificate to a certificate context and then adds the context to the certificate store.
CertAddSerializedElementToStore | Adds the serialized certificate, CRL, or CTL element to the store.
CertAddStoreToCollection | Adds a sibling certificate store to a collection store.
CertCloseStore | Closes a certificate store handle.
CertControlStore | Notifies application when a change has been made to the persisted store, re-syncs the cached store with the persisted store and commits changes made in the cached store.
CertCreateCertificateContext | Creates a certificate context from an encoded certificate. The created context is not put in a certificate store.
CertCreateContext | Creates the specified context from the encoded bytes. The new context is not put into a store.
CertDeleteCertificateFromStore | Deletes a certificate from the certificate store.
CertDuplicateCertificateContext | Duplicates a certificate context by incrementing the reference count.
CertDuplicateStore | Duplicates a store context by incrementing reference count.
CertEnumCertificateContextProperties | Enumerates the properties for the specified certificate context.
CertEnumCertificatesInStore | Enumerates the certificate contexts in the certificate store.
CertEnumPhysicalStore | Enumerates the physical stores for a specified system store.
CertEnumSystemStore | Enumerates all available system stores.
CertEnumSystemStoreLocation | Enumerates all of the locations that have an available system store.
CertFindCertificateInStore | Finds the first or next, certificate context in the certificate store matching a given criteria.
CertFreeCertificateContext | Frees a certificate context.
CertGetCertificateContextProperty | Gets a property for the specified certificate context.
CertGetIssuerCertificateFromStore | Gets a certificate context from the certificate store for the fist, or next, issuer of the specified subject certificate.
CertGetStoreProperty | Gets a certificate store property
CertGetSubjectCertificateFromStore | Gets the subject certificate context, uniquely identified by its issuer and serial number, from the certificate store.
CertOpenStore | Opens a certificate store using the specified store provider.
CertOpenSystemStore | Opens a system certificate store based on a system name.
CertRegisterPhysicalStore | Adds a physical store to a system store collection.
CertRegisterSystemStore | Registers a system store.
CertRemoveStoreFromCollection | Removes a sibling certificate store from a collection store.
CertSaveStore | Saves a certificate store.
CertSerializeCertificateStoreElement | Serializes the certificate context's encoded certificate and its properties.
CertSetCertificateContextProperty | Sets a property for the specified certificate context.
CertSetStoreProperty | Sets a store property.
CertUnregisterPhysicalStore | Removes a physical store from a system store collection.
CertUnregisterSystemStore | Unregisters a system store.
CertVerifySubjectCertificateContext | Performs the enabled verification checks on the subject certificate using the issuer.


Certificate Revocation List Functions

These Win32® functions help you to manage the storage and retrieval of certificate revocation lists.

Function | Description
CertAddCRLContextToStore | Adds a CRL context to the certificate store.
CertAddCRLLinkToStore | Adds a link in a store to a CRL context in a different store.
CertAddEncodedCRLToStore | Converts the encoded CRL to a CRL context and then adds the context to the certificate store.
CertCreateCRLContext | Creates a CRL context from an encoded CRL. The created context is not put in a certificate store.
CertDeleteCRLFromStore | Deletes a CRL from the certificate store.
CertDuplicateCRLContext | Duplicates a CRL context by incrementing the reference count.
CertEnumCRLContextProperties | Enumerates the properties for the specified CRL context.
CertEnumCRLsInStore | Enumerates the CRL contexts in a store.
CertFindCRLInStore | Finds the first or next, CRL context in the certificate store that matches a specific criteria.
CertFreeCRLContext | Frees a CRL context.
CertGetCRLContextProperty | Gets a property for the specified CRL context.
CertGetCRLFromStore | Gets the first, or next, CRL context from the certificate store for the specified issuer certificate.
CertSerializeCRLStoreElement | Serializes the CRL context's encoded CRL and its properties.
CertSetCRLContextProperty | Sets a property for the specified CRL context.


Certificate Trust List Functions

These Win32® functions help you to manage the storage and retrieval of certificate trust lists.

Function | Description
CertAddCTLContextToStore | Adds a CTL context to the certificate store.
CertAddCTLLinkToStore | Adds a link in a store to a CRL context in a different Store.
CertAddEncodedCTLToStore | Converts the encoded CTL to a CTL context and then adds the context to the certificate store.
CertCreateCTLContext | Creates a CTL context from an encoded certificate trust list. The created context is not put in a certificate store.
CertDeleteCTLFromStore | Deletes a CTL from the certificate store.
CertDuplicateCTLContext | Duplicates a CTL context by incrementing the reference count.
CertEnumCTLContextProperties | Enumerates the properties for the specified CTL context.
CertEnumCTLsInStore | Enumerates the CTL contexts in the certificate store.
CertEnumSubjectInSortedCTL | Enumerates through the TrustedSubjects in a sorted CTL context.
CertFindCTLInStore | Finds the first, or next, CTL context in the certificate store that matches a specific criteria.
CertFindSubjectInSortedCTL | Attempts to find the specified subject in a sorted CTL.
CertFreeCTLContext | Frees a CTL context.
CertGetCTLContextProperty | Gets a property for the specified CTL context.
CertSerializeCTLStoreElement | Serializes the CTL context's encoded CTL and its properties.
CertSetCTLContextProperty | Sets a property for the specified CTL context.


CertAddCertificateContextToStore

The CertAddCertificateContextToStore function adds a certificate context to the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertAddCertificateContextToStore(
  HCERTSTORE hCertStore,            // in
  PCCERT_CONTEXT pCertContext,      // in
  DWORD dwAddDisposition,           // in
  PCCERT_CONTEXT *ppStoreContext    // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
pCertContext
Pointer to the certificate context that is to be added.
dwAddDisposition
Value that specifies the action to take if a matching certificate or a link to a matching certificate already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching certificate or a link to a matching certificate exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching certificate or a link to a matching certificate exists, that existing certificate or link is used and properties from the new certificate are added. The function does not fail, but it does not add a new context. If ppCertContext is not NULL, the existing context is duplicated.

If a matching certificate or a link to a matching certificate does not exist, a new certificate is added.

CERT_STORE_ADD_REPLACE_EXISTING
If a link to a matching certificate exists, that existing certificate or link is deleted and a new certificate is created and added to the store. If a matching certificate or a link to a matching certificate does not exist, a new link is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching certificate or link to a matching certificate. A new certificate is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
If a matching certificate exists in the store, the existing context is deleted before creating and adding the new context. The new added context inherits properties from the existing certificate
CERT_STORE_ADD_NEWER
If a matching certificate or a link to a matching certificate exists, compares the NotBefore times on the certificates. If the existing certificate has a NotBefore time less than the NotBefore time on the new certificate, the old certificate or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing certificate has a NotBefore time greater than or equal to the NotBefore time on the certificate to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching certificate or a link to a matching certificate is not found in the store, a new certificate is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
The action is the same as for CERT_STORE_ADD_NEWER. However if an older certificate is replaced, the properties of the older certificate are incorporated into the replacement certificate.
ppStoreContext
A pointer to a pointer to the copy to be made of the certificate that was added to the store.

ppStoreContext can be NULL, indicating that the caller does not want a copy of the added certificate. If a copy is made, it must be freed by using CertFreeCertificateContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
Returned if CERT_STORE_ADD_NEW is set and the certificate already exists in the store or if CERT_STORE_ADD_NEWER is set and a certificate exists in the store with a NotBefore date greater than or equal to the NotBefore date on the certificate to be added.
E_INVALIDARG
An invalid add disposition was specified by the dwAddDisposition argument.

Errors from the called functions, CertAddEncodedCertificateToStore and CertSetCertificateContextProperty may be propagated to this function.

Remarks

The certificate context is not duplicated using CertDuplicateCertContext. Instead, the function creates a new copy of the context and adds it to the store.

In addition to the encoded certificate, the function also copies the context's properties, with the exception of the CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID properties.

Example

// **********************************************************
//  Declare variables.
HCERTSTORE      hLinkStoreHandle;
HCERTSTORE      hOriginalStoreHandle;
PCCERT_CONTEXT  DesiredCert = NULL;
//************************************************************
// Open a memory store where a new certificate will be added.
// For details, see CertOpenStore.
hLinkStoreHandle = CertOpenStore(CERT_STORE_PROV_MEMORY,0,NULL,0,NULL);
//*************************************************************
// Open a system store where certificates can be found
// to add to the memory store.
// For details, see CertOpenStore.
hOriginalStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM,0,NULL,
CERT_SYSTEM_STORE_CURRENT_USER,L"MY");
//***************************************************************
// Get the first certificate in the system store.
DesiredCert=CertEnumCertificatesInStore(hOriginalStoreHandle,DesiredCert);
//***************************************************************
// Add a certificate to hLinkStoreHandle store.
if(CertAddCertificateContextToStore(
     hLinkStoreHandle,             // The store handle.
     DesiredCert,                  // A pointer to a Cert.
CERT_STORE_ADD_USE_EXISTING,  // If a matching cert exists,
// use it.
     NULL                          // Do not make any extra copy of
                                   // the certificate.
     ))
printf("A certificate has been added to the store. \n");
else
printf("A certificate was not added to the store. \n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddEncodedCertificateToStore, CertSetCertificateContextProperty


CertAddCertificateLinkToStore

[This is preliminary documentation and subject to change.]

The CertAddCertificateLinkToStore function adds a link in a certificate store to a certificate context in a different store. Instead of creating and adding a duplicate of the certificate context, this function adds a link to the original certificate wherever it may be. Because the link provides access to the original certificate context, setting an extended property in the linked certificate context changes that property as seen in the certificate's original location and by any other links to that certificate.

#include <wincrypt.h>
BOOL WINAPI CertAddCertificateLinkToStore(
  HCERTSTORE hCertStore,                // in
  PCCERT_CONTEXT pCertContext,          // in
  DWORD dwAddDisposition,               // in
  PCCERT_CONTEXT *ppStoreContext        // out optional
);

Parameters

hCertStore
Handle to the certificate store where the link is to be added.
pCertContext
Pointer to the certificate context that is to be linked.
dwAddDisposition
Value that specifies the action if a matching certificate or a link to a matching certificate already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching certificate or a link to a matching certificate exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching certificate or a link to a matching certificate exists, the existing certificate is used. The function does not fail, but no new link is added. If no matching certificate or link to a matching certificate exists, a new link is added.
CERT_STORE_ADD_REPLACE_EXISTING
If a link to a matching certificate exists, that existing link is deleted and a new link is created and added to the store. If no matching certificate or link to a matching certificate exists, one is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching certificate or link to a matching certificate. A new link is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_NEWER
If a matching certificate or a link to a matching certificate exists, compares the NotBefore times on the certificates. If the existing certificate has a NotBefore time less than the NotBefore time on the new certificate, the old link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing certificate has a NotBefore time greater than or equal to the NotBefore time on the certificate to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching certificate or a link to a matching certificate is not found in the store, the function adds a new link to the store.

ppStoreContext
Pointer to a pointer to a copy of the link created. ppStoreContext can be NULL to indicate that a copy of the link is not needed. If a copy of the link is created, that copy must be freed using CertFreeCertificateContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the code for any failures using the following error codes:

Error code | Description
CRYPT_E_EXISTS | For a dwAddDisposition of CERT_STORE_ADD_NEW, the certificate already exists in the store.
E_INVALIDARG | Invalid add disposition specified by the dwAddDisposition argument.

Remarks

Links cannot be added to a store opened as a collection. Stores opened as collections include all stores opened with CertOpenSystemStore or CertOpenStore using CERT_STORE_PROV_SYSTEM or CERT_STORE_PROV_COLLECTION. Also see CertAddStoreToCollection.

If links are used and CertCloseStore is called with CERT_CLOSE_STORE_FORCE_FLAG, the store using links must be closed before the store containing the original contexts is closed. If CERT_CLOSE_STORE_FORCE_FLAG is not used, the two stores may be closed in either order.

Example

HCERTSTORE      hLinkStoreHandle;
HCERTSTORE      hOriginalStoreHandle;
PCCERT_CONTEXT  DesiredCert = NULL;
// Open a memory store where links will be added.
// For details, see CertOpenStore.
hLinkStoreHandle = CertOpenStore(
CERT_STORE_PROV_MEMORY,0,NULL,0,NULL);
// Open a system store where certificates can be found
// so that links can be added to hLinkStore.
// For details, see CertOpenStore.
hOriginalStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");

// Get the first certificate in the system store.
DesiredCert= CertEnumCertificatesInStore(
hOriginalStoreHandle,DesiredCert);
// Add a link to the certificate to hLinkStoreHandle store.
if(CertAddCertificateLinkToStore(
     hLinkStoreHandle,             // The store handle.
     DesiredCert,                  // A pointer to a Cert.
CERT_STORE_ADD_USE_EXISTING,  // If a matching cert exists,
// use it.
     NULL                          // Do not make any extra copy of
                                   // the certificate.
     ))
printf("A link has been added to the store. \n");
else
printf("A new link to a cert was not added to the store. \n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertOpenSystemStore, CertAddStoreToCollection, CertAddCRLLinkToStore, CertAddCTLLinkToStore, CertFreeCertificateContext


CertAddCRLContextToStore

The CertAddCRLContextToStore function adds a certificate revocation list (CRL) context to the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertAddCRLContextToStore(
  HCERTSTORE hCertStore,                   // in
  PCCRL_CONTEXT pCrlContext,               // in
  DWORD  dwAddDisposition,                 // in
  PCCRL_CONTEXT *ppStoreContext            // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
pCrlContext
Pointer to the CRL context that is to be added.
dwAddDisposition
Value that specifies the action to take if a matching CRL or a link to a matching CRL already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching CRL or a link to a matching CRL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching CRL or a link to a matching CRL exists, that existing CRL is used and properties from the new CRL are added. The function does not fail, but no new CRL is added. If ppCertContext is not NULL, the existing context is duplicated.

If a matching CRL or a link to a matching CRL does not exist, a new CRL is added.

CERT_STORE_ADD_REPLACE_EXISTING
If a matching CRL or a link to a matching CRL exists, the existing CRL or link is deleted and a new CRL is created and added to the store. If a matching CRL or a link to a matching CRL does not exist, one is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching CRL or link to a matching CRL. A new CRL is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES.
If a matching CRL exists in the store, the existing context is deleted before creating and adding the new context. The added context inherits properties from the existing CRL
CERT_STORE_ADD_NEWER
If a matching CRL or a link to a matching CRL exists, the function compares the ThisUpdate times on the CRLs. If the existing CRL has a ThisUpdate time less than the ThisUpdate time on the new CRL, the old CRL or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CRL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CRL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CRL or a link to a matching CRL is not found in the store, a new CRL is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES.
Action is the same as for CERT_STORE_ADD_NEWER except that if an older CRL is replaced, the properties of the older CRL are incorporated into the replacement CRL.
ppCrlContext
Pointer to a pointer to the decoded CRL context. This is an optional parameter, and can be NULL, indicating that the caller does not want a copy of the added or existing CRL. If a copy is made, that context must be freed by using CertFreeCRLContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
This error is returned if CERT_STORE_ADD_NEW is set and the CRL already exists in the store or if CERT_STORE_ADD_NEWER is set and a CRL exists in the store with a ThisUpdate date greater than or equal to the ThisUpdate date on the CRL to be added.
E_INVALIDARG
The dwAddDisposition argument specified an invalid add disposition.

Errors from the called functions CertAddEncodedCRLToStore and CertSetCRLContextProperty may be propagated to this function.

Remarks

The CRL context is not duplicated using CertDuplicateCRLContext. Instead, a new copy is created and added to the store. In addition to the encoded CRL, the function copies the context's properties.

Example

See CertAddCertificateContextToStore

Change all references to "certificate" in the example code to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddEncodedCRLToStore, CertSetCRLContextProperty


CertAddCRLLinkToStore

[This is preliminary documentation and subject to change.]

The CertAddCRLLinkToStore function adds a link in a store to a CRL context in a different store. Instead of creating and adding a duplicate of the CRL, this function adds a link to the original CRL context wherever it may be. Since the link provides access to an original CRL context, setting an extended property in the linked CRL context changes the property as seen in the CRL's original location and by any other links to that CRL.

#include <wincrypt.h>
BOOL WINAPI CertAddCRLLinkToStore(
  HCERTSTORE hCertStore,                   // in
  PCCRL_CONTEXT pCRLContext,               // in
  DWORD dwAddDisposition,                  // in
  PCCRL_CONTEXT *ppStoreContext            // out optional
);

Parameters

hCertStore
Handle to the certificate store where the link is to be added.
pCRLContext
Pointer to the CRL context that is to be linked.
dwAddDisposition
Value that specifies the action to take if a matching CRL or a link to a matching CRL exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching CRL or a link to a matching CRL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching CRL or a link to a matching CRL exists that existing link is used. The function does not fail, but no new link is added. If a matching CRL or link to a CRL does not exist, a new link is added.
CERT_STORE_ADD_REPLACE_EXISTING
If a link to the matching CRL exists, that existing link is deleted and a new link is created and added to the store. If a matching CRL or a link to a matching CRL does not exist, a new link is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching CRL or link to a matching CRL. A new link is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_NEWER
If a matching CRL or a link to a matching CRL exists, the ThisUpdate times on the CRLs are compared. If the existing CRL has a ThisUpdate time less than the ThisUpdate time on the new CRL, the old link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CRL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CRL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CRL or a link to a matching CRL is not found in the store, a new link is added to the store.

ppStoreContext
Pointer to a pointer of a copy of the link created. ppStoreContext can be NULL to indicate that a copy of the link is not needed. If a copy of the link is created, that copy must be freed using CertFreeCRLContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the code for any failures using the following error codes:

Error code | Description
CRYPT_E_EXISTS | For a dwAddDisposition of CERT_STORE_ADD_NEW, the CTL already exists in the store.
E_INVALIDARG | Invalid add disposition specified by the dwAddDisposition argument.

Remarks

Links cannot be added to a store that is opened as a collection. Stores opened as collections include all stores opened with CertOpenSystemStore or CertOpenStore using CERT_STORE_PROV_SYSTEM or CERT_STORE_PROV_COLLECTION. Also see CertAddStoreToCollection.

If links are used and CertCloseStore is called with CERT_CLOSE_STORE_FORCE_FLAG, the store using links must be closed before the store containing the original contexts can be closed. If CERT_CLOSE_STORE_FORCE_FLAG is not used, the two stores may be closed in either order.

Example

See the example with CertAddCertificateLinkToStore. This example will hold for CertAddCRLLinkToStore if all the references to "certificate" are changed to "CRL."

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertOpenSystemStore, CertAddStoreToCollection, CertAddCTLLinkToStore, CertAddCertificateLinkToStore, CertFreeCRLContext


CertAddCTLContextToStore

The CertAddCTLContextToStore function adds a CTL context to the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertAddCTLContextToStore(
  HCERTSTORE hCertStore,                 // in
  PCCTL_CONTEXT pCtlContext,             // in
  DWORD dwAddDisposition,                // in
  PCCTL_CONTEXT *ppStoreContext          // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
pCtlContext
Pointer to the CTL context that is to be added.
dwAddDisposition
Value that specifies the action to take if a matching CTL or a link to a matching CTL already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching CTL or a link to a matching CTL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching CTL or a link to a matching CTL exists, that existing CTL is used and properties from the new CTL are added. The function does not fail, but no new CTL is added. If ppCertContext is not NULL, the existing context is duplicated.

If a matching CTL or a link to a matching CTL does not exist, a new CTL is added.

CERT_STORE_ADD_REPLACE_EXISTING
If a matching CTL or a link to a matching CTL exists, the existing CTL or link is deleted and a new CTL is created and added to the store. If a matching CTL or a link to a matching CTL does not exist, one is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching CTL or link to a matching CTL . A new CTL is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES
If a matching CTL exists in the store, that existing context is deleted before creating and adding the new context. The added context inherits properties from the existing CTL
CERT_STORE_ADD_NEWER
If a matching CTL or a link to a matching CTL exists, the ThisUpdate times on the CTLs are compared. If the existing CTL has a ThisUpdate time less than the ThisUpdate time on the new CTL, the old CTL or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CTL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CTL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CTL or a link to a matching CTL is not found in the store, a new CTL is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
Action is the same as for CERT_STORE_ADD_NEWER except that if an older CTL is replaced, the properties of the older CTL are incorporated into the replacement CTL.
ppCTLContext
Pointer to a pointer to the decoded CTL context. This is an optional parameter that can be NULL, indicating that the caller does not want a copy of the added or existing CTL. If a copy is made, that context must be freed by using CertFreeCTLContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
This error is returned if CERT_STORE_ADD_NEW is set and the CTL exists in the store or if CERT_STORE_ADD_NEWER is set and a CTL exists in the store with a ThisUpdate date greater than or equal to the ThisUpdate date on the CTL to be added.
E_INVALIDARG
An invalid add disposition was specified by the dwAddDisposition argument.

Errors from the called functions CertAddEncodedCRLToStore and CertSetCRLContextProperty may be propagated to this function.

Remarks

The CTL context is not duplicated using CertDuplicateCTLContext. Instead, a new copy is created and added to the store. In addition to the encoded CTL, the context's properties are copied.

Example

See CertAddCertificateContextToStore

Change all references to ''certificate" in the example code to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddEncodedCTLToStore, CertSetCTLContextProperty


CertAddCTLLinkToStore

[This is preliminary documentation and subject to change.]

The CertAddCTLLinkToStore function adds a link in a store to a CTL context in a different store. Instead of creating and adding a duplicate of a CTL context, this function adds a link to the original CTL context wherever it may be. Since the link provides access to the original CTL context, setting an extended property in the linked CTL context changes that property as seen in the original CTL's location and by any other links to that CTL. .

#include <wincrypt.h>
BOOL WINAPI CertAddCTLLinkToStore(
  HCERTSTORE hCertStore,                   // in
  PCTL_CONTEXT pCTLContext,                // in
  DWORD dwAddDisposition,                  // in
  PCCTL_CONTEXT *ppStoreContext            // out optional
);

Parameters

hCertStore
Handle to the certificate store where the link is to be added.
pCTLContext
Pointer to the CTL context that is to be linked.
dwAddDisposition
Value that specifies the action to take if a matching CTL or a link to a matching CTL already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW
If a matching CTL or a link to a matching CTL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching CTL or a link to a matching CTL exists that existing link is used. The function does not fail, but no new link is added. If a matching CTL or link to a CTL does not exist, a new link is added.
CERT_STORE_ADD_REPLACE_EXISTING
If a link to the matching CTL exists, that existing link is deleted and a new link is created and added to the store. If a matching CTL or a link to a matching CTL does not exist, a new link is added.
CERT_STORE_ADD_ALWAYS
Makes no check for an existing matching CTL or link to a matching CTL. A new link is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_NEWER
If a matching CTL or a link to a matching CTL exists, the ThisUpdate times on the CTLs are compared. If the existing CTL has a ThisUpdate time less than the ThisUpdate time on the new CTL, the old link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CTL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CTL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CTL or a link to a matching CTL is not found in the store, a new link is added to the store.

ppStoreContext
Pointer to a pointer to a copy of the link created. ppStoreContext can be NULL to indicate that a copy of the link is not needed. If a copy of the link is created, that copy must be freed using CertFreeCTLContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the code for any failures using the following error codes:

Error code | Description
CRYPT_E_EXISTS | For a dwAddDisposition of CERT_STORE_ADD_NEW, the CTL already exists in the store.
E_INVALIDARG | Invalid add disposition specified by the dwAddDisposition argument.

Remarks

Links cannot be added to a store that is opened as a collection. Stores opened as collections include all stores opened with CertOpenSystemStore or CertOpenStore using CERT_STORE_PROV_SYSTEM or CERT_STORE_PROV_COLLECTION. Also see CertAddStoreToCollection.

When links are used and CertCloseStore is called with CERT_CLOSE_STORE_FORCE_FLAG, the store using links must be closed before the store containing the original contexts is closed. If CERT_CLOSE_STORE_FORCE_FLAG is not used, the two stores may be closed in either order.

Example

See the example with CertAddCertificateLinkToStore. This example will hold for CertAddCTLLinkToStore if all the references to "certificate" are changed to "CTL."

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertOpenSystemStore, CertAddStoreToCollection, CertAddCRLLinkToStore, CertAddCertificateLinkToStore, CertFreeCTLContext


CertAddEncodedCertificateToStore

The CertAddEncodedCertificateToStore function creates a certificate context from an encoded certificate and adds it to the certificate store. CertAddEncodedCertificateToStore also makes a copy of the encoded certificate before adding it to the store

#include <wincrypt.h>
BOOL WINAPI CertAddEncodedCertificateToStore(
  HCERTSTORE hCertStore,                 // in
  DWORD dwCertEncodingType,              // in
  const BYTE *pbCertEncoded,             // in
  DWORD cbCertEncoded,                   // in
  DWORD dwAddDisposition,                // in
  PCCERT_CONTEXT *ppCertContext          // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
dwCertEncodingType
Type of encoding used on the certificate. The currently defined certificate encoding type is X509_ASN_ENCODING.
pbCertEncoded
Pointer to the encoded certificate that is to be added to the certificate store.
cbCertEncoded
Size, in bytes, of the encoded certificate to be added to the certificate store.
dwAddDisposition
Value that specifies the action to take if a matching certificate or link to a matching certificate exists in the store. Currently defined disposition values are:
CERT_STORE_ADD_NEW
If a matching certificate or a link to a matching certificate exists in the store, the operation fails and GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING
If a matching certificate or a link to a matching certificate exists, that existing certificate or link is used and properties from the new certificate are added. The function does not fail, but it does not add a new context. If ppCertContext is not NULL, the existing context is duplicated.

If a matching certificate or link to a matching certificate does not exist, a new certificate is added.

CERT_STORE_ADD_REPLACE_EXISTING
If a matching certificate or link to a matching certificate exists in the store, the existing certificate or link is deleted and a new certificate is created and added to the store. If a matching certificate or link to a matching certificate does not exist, a new certificate is created and added to the store.
CERT_STORE_ADD_ALWAYS
Does not check to see whether a matching certificate or a link to a matching certificate already exists. A new certificate is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES.
If a matching certificate exists in the store, that existing context is deleted before creating and adding the new context. The added context inherits properties from the existing certificate
CERT_STORE_ADD_NEWER
If a matching certificate or a link to a matching certificate exists, compares the NotBefore times on the certificates. If the existing certificate has a NotBefore time less than the NotBefore time on the new certificate, the old certificate or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing certificate has a NotBefore time greater than or equal to the NotBefore time on the certificate to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching certificate or a link to a matching certificate is not found in the store, a new certificate is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES
The action is the same as for CERT_STORE_ADD_NEWER except that if an older certificate is replaced, the properties of the older certificate are incorporated into the replacement certificate.
ppCertContext
Pointer to a pointer to the decoded certificate context. This is an optional parameter that can be NULL, indicating that the caller does not want a copy of the new or existing certificate. When a copy is made, its context must be freed by using CertFreeCertificateContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
This error is returned if CERT_STORE_ADD_NEW is set and the certificate already exists in the store or if CERT_STORE_ADD_NEWER is set and a there is a certificate in the store with a NotBefore date greater than or equal to the NotBefore date on the certificate to be added.
CRYPT_E_OSS_ERROR
ASN.1 decoding error occurred. To get the OSS error, subtract the value of CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG
An invalid add disposition was specified by the dwAddDisposition argument or an invalid certificate encoding type was specified. Currently only X509_ASN_ENCODING is supported.

Example

// The function handle_error() is defined in a separate file.
HCERTSTORE      hMemoryStoreHandle;
HCERTSTORE      hStoreHandle;
PCCERT_CONTEXT  DesiredCert = NULL;
// Open a memory store where the certificate will be added.
// See CertOpenStore for details.
if(hMemoryStoreHandle = CertOpenStore(
CERT_STORE_PROV_MEMORY,0,NULL,0,NULL))
printf("Memory store open. \n");
else
handle_error("Store did not open.");
// Open a system store to get a certificate.
if(hStoreHandle = CertOpenSystemStore(0,"CA"))
// The system store opened. Continue.
printf("System store open.\n");
else
handle_error("The system store did not open.");
// Get the first certificate in the system store.
if(DesiredCert= CertEnumCertificatesInStore(
hStoreHandle,DesiredCert))
// A certificate was retrieved. Continue.
printf("A certificate has been retrieved.\n");
else
handle_error("A certificate could not be retrieved. Perhaps the store is empty.");
// Add the encoded certificate to the store()
if(CertAddEncodedCertificateToStore(
   hMemoryStoreHandle,         // Store where certificate
                               // is to be added.
   X509_ASN_ENCODING,          // The encoding type used.
DesiredCert->pbCertEncoded, // The encoded certificate
// from the system store certificate.
DesiredCert->cbCertEncoded, // The length of that encoded cert.
CERT_STORE_ADD_USE_EXISTING,// Flag to indicate that if a
// matching cert already exists in
// the store, it should be used.
   NULL                        // No duplicate cert is to be
                               // created.
   ))
// A certificate was added to the memory store. Continue.
printf("The certificate has been added.\n");
else
handle_error("The certificate was not added.");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddCertificateContextToStore


CertAddEncodedCRLToStore

The CertAddEncodedCRLToStore function creates a CRL context from an encoded CRL and adds it to the certificate store. The function makes a copy of the CRL context before adding it to the store.

#include <wincrypt.h>
BOOL WINAPI CertAddEncodedCRLToStore(
  HCERTSTORE hCertStore,               // in
  DWORD dwCertEncodingType,            // in
  const BYTE *pbCrlEncoded,            // in
  DWORD cbCrlEncoded,                  // in
  DWORD dwAddDisposition,              // in
  PCCRL_CONTEXT *ppCrlContext          // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
dwCertEncodingType
Type of encoding used on the CRL. The currently defined encoding type is X509_ASN_ENCODING (0x00000001).
pbCrlEncoded
Pointer to the encoded CRL that is to be added to the certificate store.
cbCrlEncoded
Size, in bytes, of the encoded CRL to be added to the certificate store.
dwAddDisposition
Value that specifies the action to take if a matching CRL or a link to a matching CRL already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW.
If a matching CRL or a link to a matching CRL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING.
If a matching CRL or a link to a matching CRL exists, that existing CRL is used and properties from the new CRL are added. The function does not fail, but no new CRL is added. If ppCertContext is not NULL, the existing context is duplicated.

If a matching CRL or a link to a matching CRL does not exist, a new CRL is added.

CERT_STORE_ADD_REPLACE_EXISTING.
If a matching CRL or a link to a matching CRL exists, that existing CRL or link is deleted and a new CRL is created and added to the store. If a matching CRL or a link to a matching CRL does not exist, one is added.
CERT_STORE_ADD_ALWAYS.
Makes no check for an existing matching CRL or link to a matching CRL. A new CRL is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES.
If a matching CRL exists in the store, that existing context is deleted before creating and adding the new context. The new context inherits properties from the existing CRL
CERT_STORE_ADD_NEWER
If a matching CRL or a link to a matching CRL exists, the ThisUpdate times on the CRLs are compared. If the existing CRL has a ThisUpdate time less than the ThisUpdate time on the new CRL, the old CRL or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CRL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CRL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CRL or a link to a matching CRL is not found in the store, a new CRL is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES.
The action is the same as for CERT_STORE_ADD_NEWER except that if an older CRL is replaced, the properties of the older CRL are incorporated into the replacement CRL.
ppCrlContext
Pointer to a pointer to the decoded CRL context. This is an optional parameter that can be NULL, indicating that the caller does not want a copy of the new or existing CRL. If a copy is made, that context must be freed by using CertFreeCRLContext.

Return Values

The function returns TRUE if the function succeeded, FALSE if the function failed.

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
This error is returned if CERT_STORE_ADD_NEW is set and the CRL already exists in the store or if CERT_STORE_ADD_NEWER is set and a there is a CRL in the store with a ThisUpdate time greater than or equal to the ThisUpdate time on the CRL to be added.
CRYPT_E_OSS_ERROR
An ASN.1 decoding error occurred. To get the OSS error, subtract the value of CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG
An invalid add disposition was specified by the dwAddDisposition argument or an invalid encoding type was specified. Currently only encoding type X509_ASN_ENCODING is supported.

Example

See CertAddEncodedCertificateToStore. In that example, change all references from "certificate" to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddCRLContextToStore


CertAddEncodedCTLToStore

The CertAddEncodedCTLToStore function creates a CTL context from an encoded CTL and adds it to the certificate store. The function makes a copy of the CTL context before adding it to the store.

#include <wincrypt.h>
BOOL WINAPI CertAddEncodedCTLToStore(
  HCERTSTORE hCertStore,                   // in
  DWORD dwMsgAndCertEncodingType,          // in
  const BYTE *pbCtlEncoded,                // in
  DWORD cbCtlEncoded,                      // in
  DWORD dwAddDisposition,                  // in
  PCCTL_CONTEXT *ppCtlContext              // out, optional
);

Parameters

hCertStore
Handle to the certificate store.
dwMsgAndCertEncodingType
The type of encoding used. The message encoding pertains to the signed message and to the encoded CTL. The certificate encoding pertains to certificates that might be included in the signed message. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation as shown in the following example:

X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbCtlEncoded
Pointer to the encoded CTL that is to be added to the certificate store.
cbCtlEncoded
Size, in bytes, of the encoded CTL to be added to the certificate store.
dwAddDisposition
Value that specifies the action to take if a matching CTL or a link to a matching CTL already exists in the store. Currently defined disposition values and their uses are:
CERT_STORE_ADD_NEW.
If a matching CTL or a link to a matching CTL exists, the operation fails. GetLastError returns CRYPT_E_EXISTS.
CERT_STORE_ADD_USE_EXISTING.
If a matching CTL or a link to a matching CTL exists, that existing CTL is used and properties from the new CTL are addedIf a matching certificate or a link to a matching certificate exists, that existing certificate or link is used and properties from the new certificate are added. The function does not fail, but it does not add a new context. If ppCertContext is not NULL, the existing context is duplicated.

The function does not fail, but no new CTL is added. If ppCertContext is not NULL, the existing context is duplicated.

If a matching CTL or a link to a matching CTL does not exist, a new CTL is added.

CERT_STORE_ADD_REPLACE_EXISTING.
If a matching CTL or a link to a matching CTL exists, that existing CTL or link is deleted and a new CTL is created and added to the store. If a matching CTL or a link to a matching CTL does not exist, one is added.
CERT_STORE_ADD_ALWAYS.
Makes no check for an existing matching CTL or a link to a matching CTL. A new CTL is always added to the store. This may lead to duplicates in a store.
CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES.
If a matching CTL exists in the store, that existing context is deleted before creating and adding the new context. The new context inherits properties from the existing CTL.
CERT_STORE_ADD_NEWER
If a matching CTL or a link to a matching CTL exists, the ThisUpdate times on the CTLs are compared. If the existing CTL has a ThisUpdate time less than the ThisUpdate time on the new CTL, the old CTL or link is replaced just as with CERT_STORE_ADD_REPLACE_EXISTING. If the existing CTL has a ThisUpdate time greater than or equal to the ThisUpdate time on the CTL to be added, the function fails with GetLastError returning CRYPT_E_EXISTS.

If a matching CTL or a link to a matching CTL is not found in the store, a new CTL is added to the store.

CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES.
The action is the same as for CERT_STORE_ADD_NEWER except that if an older CTL is replaced, the properties of the older CTL are incorporated into the replacement CTL.
ppCtlContext
Pointer to a pointer to the decoded CTL context. This is an optional parameter that can be NULL, indicating that the caller does not want a copy of the added or existing CTL. If a copy is made, it must be freed by using CertFreeCTLContext.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError returns the reason for any failures using the following error codes:

CRYPT_E_EXISTS
This error is returned if CERT_STORE_ADD_NEW is set and the CTL already exists in the store or if CERT_STORE_ADD_NEWER is set and a there is a CTL in the store with a ThisUpdate time greater than or equal to the ThisUpdate time on the CTL to be added.
CRYPT_E_OSS_ERROR
An ASN.1 decoding error occurred. To get the OSS error, subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG
An invalid add disposition was specified by the dwAddDisposition argument or an invalid encoding type was specified. Currently only X509_ASN_ENCODING and PKCS_7_ASN_ENCODING are supported.

Example

See CertAddEncodedCertificateToStore. In that example, change all references to "certificate" to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddCTLContextToStore


CertAddSerializedElementToStore

The CertAddSerializedElementToStore function adds the serialized certificate, CRL, or CTL element to the store. The serialized element contains the encoded certificate, CRL, or CTL and its properties, such as, CERT_KEY_PROV_INFO_PROP_ID.

#include <wincrypt.h>
BOOL WINAPI CertAddSerializedElementToStore(
  HCERTSTORE hCertStore,             // in
  const BYTE *pbElement,             // in
  DWORD cbElement,                   // in
  DWORD dwAddDisposition,            // in
  DWORD dwFlags,                     // in
  DWORD dwContextTypeFlags,          // in
  DWORD *pdwContextType,             // out, optional
  const void **ppvContext            // out, optional
);

Parameters

hCertStore
Handle to the certificate store. If hCertStore is NULL, creates a certificate, CRL, or CTL context not residing in any store.
pbElement
Pointer to the certificate, CRL, or CTL element to be added to the certificate store.
cbElement
Size, in bytes, of the element to be added to the certificate store.
dwAddDisposition
Specifies the action to take if the certificate, CRL, or CTL already exists in the store. Currently defined disposition values are shown in the following table:
Disposition | Value
CERT_STORE_ADD_NEW | 0x00000001
CERT_STORE_ADD_USE_EXISTING | 0x00000002
CERT_STORE_ADD_REPLACE_EXISTING | 0x00000003
CERT_STORE_ADD_ALWAYS | 0x00000004

For dwAddDisposition == CERT_STORE_ADD_NEW the operation fails if the certificate, CRL, or CTL already exists in the store. LastError is set to CRYPT_E_EXISTS.

For dwAddDisposition == CERT_STORE_ADD_USE_EXISTING, if the certificate, CRL, or CTL already exists, then it is used and if ppvContext is not NULL, the existing context is duplicated. It only copies the properties that don't already exist. The SHA1 and MD5 hash propoerties aren't copied.

For dwAddDisposition == CERT_STORE_ADD_REPLACE_EXISTING, if the certificate, CRL, or CTL already exists, then the existing certificate, CRL, or CTL context is deleted before creating and adding the new context.

For dwAddDisposition == CERT_STORE_ADD_ALWAYS, no check is made to see if the certificate, CRL, or CTL already exists. A new certificate, CRL, or CTL context is always created. This may lead to duplicates in the store.

CertGetCRLFromStore, or CertGetSubjectCertificateFromStore is called to determine if the element already exists in the store, if that check is necessary.

dwFlags
This parameter is not currently used. Zero should be passed for its value when this function is called.
dwContextTypeFlags
Specifies the set of allowable contexts. For example, to add either a certificate, CRL, or CTL, set dwContextTypeFlags to: CERT_STORE_CERTIFICATE_CONTEXT_FLAG | CERT_STORE_CRL_CONTEXT_FLAG.

Currently defined context type flags are shown in the following table:
Context type flag | Value
CERT_STORE_ALL_CONTEXT_FLAG | 0xFFFFFFFF
CERT_STORE_CERTIFICATE_CONTEXT_FLAG | 0x00000001
CERT_STORE_CRL_CONTEXT_FLAG | 0x00000002
CERT_STORE_CTL_CONTEXT_FLAG | 0x00000004

pdwContextType
Pointer to the context type of the added serialized element. This is an optional parameter, and can be NULL, indicating that the caller does not want the context type.

Currently defined context types are shown in the following table:
Context type | Value
CERT_STORE_CERTIFICATE_CONTEXT | 0x00000001
CERT_STORE_CRL_CONTEXT | 0x00000002
CERT_STORE_CTL_CONTEXT | 0x00000003

ppvContext
Pointer to a pointer to the decoded certificate, CRL, or CTL context. This is an optional parameter, and can be NULL, indicating that the caller does not want the context of the added or existing certificate, CRL, or CTL. When finished, the context must be freed by using CertFreeCertificateContext for a certificate and CertFreeCRLContext for a CRL.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
CRYPT_E_EXISTS | For a dwAddDisposition of CERT_STORE_ADD_NEW, the certificate, CRL, or CTL already exists in the store.
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG | Invalid add disposition specified by the dwAddDisposition argument.

Example

See CertSerializeCertificateStoreElement.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertSerializeCertificateStoreElement, CertSerializeCRLStoreElement


CertAddStoreToCollection

[This is preliminary documentation and subject to change.]

The CertAddStoreToCollection function adds a sibling certificate store to a collection certificate store.

#include <wincrypt.h>
BOOL WINAPI CertAddStoreToCollection(
  HCERTSTORE hCollectionStore,            // in
  HCERTSTORE hSiblingStore,               // in optional
  DWORD dwUpdateFlag,                     // in
  DWORD dwPriority                            // in
);

Parameters

hCollectionStore
Handle to the certificate store.
hSiblingStore
Handle of a sibling store to be added to the collection store. See Remarks.
dwUpdateFlag
Flag to indicate whether certificates, CRLs, and CTLs can be added to the new sibling store member of the collection store . Set dwUpdateFlag to CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG to enable addition or to 0 to disable additions.
dwPriority
DWORD used to set a priority level of the new store in the collection, with zero being the lowest priority. If zero is passed for this parameter, the specified store will be appended as the last store in the collection. The priority levels of the stores in a collection determine the order in which the stores are enumerated, and the search order of the stores when attempting to retrieve a certificate, CRL, or CTL. Priority levels also determine into which store of a collection a new certificate, CRL or CTL will be added. See Remarks for further information.

Return Values

TRUE is returned if a new store was added to the collection of stores. FALSE is returned if the function failed.

Remarks

A collection store has the same HCERTSTORE handle as a single store; thus, almost all functions that apply to any certificate store also apply to any collection store. Enumeration and find processes span all of the stores in a collection store; however, functions that add links to stores such as CertAddCertificateLinkToStore cannot be used with collection stores.

When a certificate, CRL, or CTL is added to a collection store, the list of sibling stores in the collection is searched in priority order to find the first store that allows adding. Adding is enabled if CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG was set in the CertAddStoreToCollection call. With any function that adds elements to a store, if a store that allows adding does not return success, the add function silently continues on to the next store.

When a collection store and its sibling stores are closed with CertCloseStore using the CERT_CLOSE_STORE_FORCE_FLAG, the collection store must be closed before its sibling stores. If the CERT_CLOSE_STORE_FORCE_FLAG is not used, the stores may be closed in any order.

Example

// handle_error() is a function defined in a separate file.
HCERTSTORE hCollectionStore;
HCERTSTORE hSiblingStore;

// Open the collection store. For details, see CertOpenStore.
if(hCollectionStore = CertOpenStore(
CERT_STORE_PROV_COLLECTION,
     0,        // For CERT_STORE_PROV_COLLECTION,
               // the rest of the parameters
               // must be 0 or NULL.
NULL,
0,
NULL))
// The collection store opened. Continue.
printf("Opened the COLLECTION Store\n");
else
handle_error("Error opening Store from disk.");
// Open a sibling store. For details, see CertOpenStore.
if(hsiblingstore = CertOpenStore(
   CERT_STORE_PROV_MEMORY,   // For the memory provider type,
   0,                        // the rest of the parameters must
   NULL,                     // be 0 or NULL.
0,
NULL))
// The memory store to be a sibling store opened. Continue.
printf("Memory store open. \n");
else
handle_error("Memory store not open.");
// Add the sibling store to the collection.
if(CertAddStoreToCollection(
hCollectionStore,
hSiblingStore,
   CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG,     // dwUpdateFlag
   3                                        // Store priority
                                            // in the collection.
   ))
// The sibling store was added to the collection. Continue.
printf("A sibling store has been added to the collection.\n");
else
handle_error("The sibling store was not added to the collection.");
//
// Work with certificates in the collection store and close the
// stores.
// Note that a find on the collection store will locate
// contexts in any of its sibling stores.
//

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRemoveStoreFromCollection


CertCloseStore

The CertCloseStore function closes a certificate store handle. There needs to be a corresponding CertCloseStore for each successful CertOpenStore and CertDuplicateStore.

#include <wincrypt.h>
BOOL WINAPI CertCloseStore(
  HCERTSTORE hCertStore,       // in
  DWORD dwFlags                // in
);

Parameters

hCertStore
A handle to the certificate store.
dwFlags
Allows for forcing store closure and/or checking whether all of the store's certificates and CRLs have been freed, and that this is the last CertCloseStore required.

The following flags are defined for these uses.
Flag name Value Description
CERT_CLOSE_STORE_
FORCE_FLAG 		0x00000001 Allows for forcing store closure and freeing of memory.
CERT_CLOSE_STORE_
CHECK_FLAG 		0x00000002 Allows for checking whether all of a store's certificates and CRLs have been freed and this is the final close store.

Return Values

TRUE if the function succeeded. FALSE if the function failed. For more details, see the "Remarks" section.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
CRYPT_E_PENDING_CLOSE | Final store closure is pending until additional context frees or store closes.

Remarks

On the final close, if the CERT_STORE_NO_CRYPT_RELEASE_FLAG wasn't set at the time the store was opened, the hCryptProv is released via CryptReleaseContext.

Note The certificate store isn't freed until all of its certificate contexts and CRL contexts have also been freed via CertFreeCertificateContext and CertFreeCRLContext respectively (unless the CERT_CLOSE_STORE_FORCE_FLAG is also specified).

To force the closure of the store with all of its memory freed, specify the CERT_STORE_CLOSE_FORCE_FLAG. This flag should be set when the caller does its own reference counting and wants everything to vanish.

To check whether all the store's certificates and CRLs have been freed and that this is the last CertCloseStore, set the CERT_CLOSE_STORE_CHECK_FLAG. When this flag is set, and certificates or CRLs or stores still need to be freed or closed, FALSE is returned with LastError set to CRYPT_E_PENDING_CLOSE. Note that the store is still closed when FALSE is returned. This is a diagnostic flag.

LastError is preserved unless CERT_CLOSE_STORE_CHECK_FLAG is set and FALSE is returned.

Example

//--------------------------------------------------------------------
// Close a certificate store using CERT_CLOSE_STORE_FORCE_FLAG and
// with CERT_CLOSE_STORE_CHECK_FLAG.
//--------------------------------------------------------------------

// handle_error() is a function defined in a separate file.
HANDLE hStoreHandle;
PCCERT_CONTEXT  DesiredCert;

// Open a certificate store. For details, see CertOpenStore.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
// The store opened. Continue.
printf("The store is open.\n");
else
   //   The store did not open. Exit to an error routine.
   handle_error("The store could not be opened.");

if(DesiredCert= CertEnumCertificatesInStore(
hStoreHandle,NULL))
printf("A certificate was retrieved. Continue.\n");
else
// A certificate was not retrieved. Exit to an error routine.
handle_error("No certificate retrieved. The store may be empty.");
// Close the store with forced freeing of open certificates.
if(CertCloseStore(
   hStoreHandle,                  // handle of store to close.
   CERT_CLOSE_STORE_FORCE_FLAG    // flag to force freeing certs.
   ))
printf("The store was properly closed. Continue.\n");
else
// The Store was not properly closed. Exit to an error routine.
handle_error("Store not properly closed. The force flag was used.");
// Re-open the certificate store. For details, see CertOpenStore.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The store was re-opened. Continue.\n");
else
// The store was not opened. Exit to an error routine.
handle_error("The store was not re-opened.");
// Get the first cert in the store.
if(DesiredCert= CertEnumCertificatesInStore(
hStoreHandle,NULL))
printf("A certificate was retrieved. Continue.\n");
else
// A certificate was not retrieved. Exit to an error routine.
handle_error("No certificate retrieved. The store may be empty.");
// Close the store again, this time, check for open certificates.
// If the function returns TRUE, no certificates remained open.
if(CertCloseStore(
hStoreHandle,                 // Handle of the store to be closed.
CERT_CLOSE_STORE_CHECK_FLAG)) // Do not force free all certs.
printf("The store was closed and no certs are still open.\n");
else{
// If the function returns FALSE, the store is closed, but one
// or more certificates remains open and must be freed by the
// application.
printf("A Certs remains open.\n");
// Free the open certificate.
if(CertFreeCertificateContext(DesiredCert))
printf("The certificate was freed. Continue.\n");
else
// The cert was not freed. Exit to an error routine.
handle_error("A certificate could not be freed.");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertOpenStore, CertDuplicateStore


CertControlStore

[This is preliminary documentation and subject to change.]

The CertControlStore function allows an application to be notified when there is a difference between the contents of a cached store and the contents of the store that is persisted to storage.

CertControlStore also provides re-synchronization of the cached store if necessary, and provides a means to commit changes made in the cached store to persisted storage. Additional functionality is planned.

#include <wincrypt.h>
BOOL WINAPI CertControlStore(
  HCERTSTORE hCertStore,                 // in
  DWORD dwFlags,                         // in
  DWORD dwCtrlType,                      // in
  void const *pvCtrlPara                 // in
);

Parameters

hCertStore
Handle to the certificate store.
dwFlags
For dwCtrlType CERT_STORE_CTRL_COMMIT, defined dwFlags are:

CERT_STORE_CTRL_COMMIT_FORCE_FLAG(0x1) forces the contents of the cache memory store to be copied to permanent storage even if it has not been changed.

CERT_STORE_CTRL_COMMIT_CLEAR_FLAG(0x2) inhibits the copying the contents of the cache memory store to permanent storage even when the store is closed.

For dwCtrlType CERT_STORE_CTRL_NOTIFY_CHANGE and CERT_STORE_CTRL_RESYNC,.dwflags is not used and must be set to 0.

dwCtrlType
Indicates the control action to be taken by CertControlStore. The interpretations of pvCtrlPara and dwFlags depend on the value of dwCtrlType. Currently, three actions are defined:
CERT_STORE_CTRL_RESYNC
The cached store is re-synchronized and made to match the persisted store.
CERT_STORE_CTRL_NOTIFY_CHANGE
Causes a signal returned in the space pointed to by pvCtrlPara to indicate that the current contents of the cached store differ from the store's persisted state.
CERT_STORE_CTRL_COMMIT
Causes any changes made to the cached store to be copied to persisted storage. If no changes were made since the cached store was opened or since the last commit, the call is ignored. The call is also ignored if the store provider is a provider that automatically persists changes immediately.
pvCtrlPara
If dwCtrlType is CERT_STORE_NOTIFY_CHANGE, pvCtrlPara is set to the address of a HANDLE where the system will write a signal when a change from the persisted state of the store is detected. The HANDLE, itself, must be initialized with a call to the function, CreateEvent.

If dwCtrlType is CERT_STORE_CTRL_RESYNC or CERT_STORE_CTRL_COMMIT, pvCtrlPara is not used and should be set to NULL.

Return Values

If dwCtrlType is CERT_STORE_NOTIFY_CHANGE, the function returns TRUE if a HANDLE for the event signal was successfully set up. FALSE is returned if the event HANDLE was not set up.

If dwCtrlType is CERT_STORE_CTRL_RESYNC, the function returns TRUE if the re-synchronization succeeded and FALSE if the re-synchronization failed.

If dwCtrlType is CERT_STORE_CTRL_COMMIT, the function returns TRUE to indicate the successful completion of the commit to persisted storage and FALSE if the commit failed.

Some providers may not support specific control types. In these cases, CertControlStore returns FALSE and GetLastError is set to ERROR_NOT_SUPPORTED.

Remarks

Re-synchronization of a store may be done at any time. It need not follow a signaled notify change event.

CERT_STORE_CTRL_NOTIFY_CHANGE is supported on registry based store providers via the RegNotifyChangeKeyValue function.

Example

HANDLE     hEvent;
HCERTSTORE hCertStore;
BOOL       fSignal;

// Initalize the event.
hEvent=CreateEvent(
NULL,
     FALSE,          // Manual reset is FALSE.
     FALSE,          // The initial state of the event is FALSE.
NULL);
// Open the MY system store. For details, see CertOpenStore.
if(hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_A, 0, NULL, 0, "MY"))
printf("The MY store is open.\n");
else
handle_error("The MY store was not opened.");
//  Call CertControlStore the first time with
//  CERT_CONTROL_STORE_NOTIFY_CHANGE.
if(CertControlStore(
    hCertStore,                    // The store to be controlled
    0,                             // Not used
CERT_STORE_CTRL_NOTIFY_CHANGE, // Control action type
    &hEvent))                      // Points to the event Handle.
                                   //  When a change is detected,
                                   //  a signal is written to the
                                   //  space pointed to by
                                   //  hHandle.
printf("Notify change worked \n");
else
handle_error("Notify change failed. \n");
// Wait for the store to change.
If(WAIT_OBJECT_0 == WaitForSingleObjectEx(
hEvent,
INFINITE,               // number of milliseconds to wait
FALSE))
fSignal = TRUE;
else
fSignal = FALSE;
if (fSignal)
// The store has changed.
// Call the function a second time with CERT_STORE_CTRL_RESYNC
if(CertControlStore(
          hCertStore,                // in, The store to be controlled
          0,                         // in, Not used.
          CERT_STORE_CTRL_RESYNC,    // in, Control action type
          NULL))                     // in, Not used with re-sync
printf("Re-sync worked. \n");
else
handle_error("Re-sync failed.");
else
{
printf("The store was not changed \n");
printf("Re-sync not needed. \n");
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CreateEvent, WaitForSingleObjectEx


CertCreateCertificateContext

The CertCreateCertificateContext function creates a certificate context from an encoded certificate. The created context is not put into a certificate store. It makes a copy of the encoded certificate within the created context.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertCreateCertificateContext(
  DWORD dwCertEncodingType,                // in
  const BYTE *pbCertEncoded,               // in
  DWORD cbCertEncoded                      // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbCertEncoded
A pointer to the encoded certificate from which the context is to be created.
cbCertEncoded
The size, in bytes, of the encoded certificate.

Return Values

If unable to decode and create the certificate context, NULL is returned. Otherwise, a pointer to a read-only CERT_CONTEXT is returned.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Remarks

The CERT_CONTEXT must be freed by calling CertFreeCertificateContext. CertDuplicateCertificateContext can be called to make a duplicate. CertSetCertificateContextProperty and CertGetCertificateContextProperty can be called to store and read properties for the certificate.

Example

// handle_error() is a function defined in a separate file.
HCERTSTORE      hStoreHandle;
PCCERT_CONTEXT  pDesiredCert = NULL;
PCCERT_CONTEXT  pCertContext = NULL;

// Open a system store to get a certificate.
if(hStoreHandle = CertOpenSystemStore(0,"MY")))
printf("System store open. Continue.\n");
else
handle_error("The store was not opened.");
// Find the first certificate in the system store.
if(pDesiredCert= CertEnumCertificatesInStore(
hStoreHandle,pDesiredCert))
printf("A certificate has been retrieved. Continue.\n");
else
handle_error("No certificate retrieved. The store may be empty.");
if(pCertContext = CertCreateCertificateContext(
   X509_ASN_ENCODING,             // The encoding type.
   pDesiredCert->pbCertEncoded,   // The encoded data from
                                  // the certificate retrieved.
pDesiredCert->cbCertEncoded))  // The length of the encoded data.
printf("A new certificate as been created. Continue. \n");
else
handle_error("A new certificate could not be created.");
// The function succeeded. The new certificate context was created
// and is pointed to by pCertContext.
// Use the certificate context as necessary.
// Free memory.
CertFreeCertificateContext(pCertContext);
printf("The program ran to completion. \n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertCreateCRLContext, CertCreateCTLContext


CertCreateContext

[This is preliminary documentation and subject to change.]

The CertCreateContext function creates the specified context from the encoded bytes.

#include <wincrypt.h>
const void * WINAPI CertCreateContext(
  DWORD dwContextType,                    // in
  DWORD dwEncodingType,                   // in
  const BYTE *pbEncoded,                  // in
  DWORD cbEncoded,                        // in
  DWORD dwFlags,                          // in
  PCERT_CREATE_CONTEXT_PARA pCreatePara   // in, optional
);

Parameters

dwContextType
Specifies the set of allowable contexts. For example, to create either a certificate, CRL, or CTL, set dwContextType to: CERT_STORE_CERTIFICATE_CONTEXT_FLAG | CERT_STORE_CRL_CONTEXT_FLAG

Currently defined context type flags are shown in the following table:
Context type | Value
CERT_STORE_ALL_CONTEXT_FLAG | 0xFFFFFFFF
CERT_STORE_CERTIFICATE_CONTEXT_FLAG | 0x00000001
CERT_STORE_CRL_CONTEXT_FLAG | 0x00000002
CERT_STORE_CTL_CONTEXT_FLAG | 0x00000004

dwEncodingType
Type of encoding used. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbEncoded
Pointer to the content to be copied (the existing encoded context).
cbEncoded
Size, in bytes, of the existing encoded context.
dwFlags
Flag values.

The following flags can be combined with a bitwise OR operation into CertCreateContext dwFlags.

CERT_CREATE_CONTEXT_NOCOPY_FLAG
The created context points directly to the pbEncoded instead of an allocated copy.
CERT_CREATE_CONTEXT_SORTED_FLAG
Creates a context with sorted entries. Currently this flag is only applicable to a CTL context.

For CTLs: the cCTLEntry in the returned CTL_INFO is always 0. CertFindSubjectInSortedCTL and CertEnumSubjectInSortedCTL must be called to find or enumerate the CTL entries.

pCreatePara
Pointer to a CERT_CREATE_CONTEXT_PARA structure.

If pCreatePara and pCreatePara->pfnFree are non-NULL pCreatePara->pfnFree is called to free the pbEncoded when the context is last freed.

If pCreatePara->pvFree is non-NULL, then pCreatePara->pvFree instead of pbEncoded is passed to the function of pCreatePara->pfnFree.

If pCreatePara or pCreatePara->pfnFree are NULL, no attempt is made to free pbEncoded.

Return Values

A pointer to the newly created context. If a NULL is returned, the function failed and the function pointed to by pCreatePara->pvFree must be called to free the created context.

Example

// EXAMPLE CODE FOR USING CertCreateContext().
// Assume pointers to an encoded data (pbEncoded) and the
// size of the encoded context (cbEnabled) are initialized.
// Declare and initialize.
CERT_CREATE_CONTEXT_PARA   CreatePara;
CreatePara.cbSize= sizeof(CERT_CREATE_CONTEXT_PARA);
CreatePara.pfnFree= NULL;
CreatePara.pvFree= NULL;
const BYTE *pbEncoded;          // Pointer to existing encoded data or
                                //   context- initialized elsewhere.
DWORD cbEnabled;                // Size of encoded context.
PCERT_CREATE_CONTEXT_PARA pCreatePara;
// Pointer to the created structure.
PCCRL_CONTEXT pReturn;          // Returns a pointer to address of
                                //   the created context.

// Function call to CertCreateContext().
pReturn= (PCCRL_CONTEXT) CertCreateContext(
CERT_STORE_CRL_CONTEXT_FLAG,
// in- dwContextType, this is a CRL.
          X509_ASN_ENCODING,    // in- dwEncodingType
          pbEncoded,            // in- Initialized elsewhere
          cbEnabled,            // in- cbEncoded- size of encoded
                                //   context.
          0,                    // in- dwFlags- to make a copy
                                //   CERT_CREATE_CONTEXT_NOCOPY_FLAG
                                //   is not set.
          pCreatePara);         // in, optional- pCreatePara
if(pReturn){  // Pointer to created context is returned.
printf("Context created.");
    }
else {        // NULL returned- function failed.
printf("CertCreateContext failed\n");
}

// Free the memory
CertFreeCRLContext(pReturn);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertCreateCRLContext

The CertCreateCRLContext function creates a CRL context from an encoded CRL. The created context is not put into a certificate store. It makes a copy of the encoded CRL within the created context.

#include <wincrypt.h>
PCCRL_CONTEXT WINAPI CertCreateCRLContext(
  DWORD dwCertEncodingType,           // in
  const BYTE *pbCrlEncoded,           // in
  DWORD cbCrlEncoded                  // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbCrlEncoded
A pointer to the encoded CRL from which the context is to be created.
cbCrlEncoded
The size, in bytes, of the encoded CRL.

Return Values

If unable to decode and create the CRL_CONTEXT, NULL is returned. Otherwise, a pointer to a read-only CRL_CONTEXT is returned.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Remarks

The CRL_CONTEXT must be freed by calling CertFreeCRLContext. CertDuplicateCRLContext can be called to make a duplicate. CertSetCRLContextProperty and CertGetCRLContextProperty can be called to store and read properties for the CRL.

Example

See CertCreateCertificateContext. In that example, change all references to "certificate" to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertCreateCertificateContext, CertCreateCTLContext


CertCreateCTLContext

The CertCreateCTLContext function creates a CTL context from an encoded CTL. The created context is not put into a certificate store. It makes a copy of the encoded CTL within the created context.

#include <wincrypt.h>
PCCTL_CONTEXT WINAPI CertCreateCTLContext(
  DWORD dwMsgAndCertEncodingType,          // in
  const BYTE *pbCtlEncoded,                // in
  DWORD cbCtlEncoded                       // in
);

Parameters

dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbCtlEncoded
A pointer to the encoded CTL from which the context is to be created.
cbCtlEncoded
The size, in bytes, of the encoded CTL.

Return Values

If unable to decode and create the CTL_CONTEXT, NULL is returned. Otherwise, a pointer to a read-only CTL_CONTEXT is returned.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | Invalid certificate encoding type. Only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING are supported.
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Remarks

The CTL_CONTEXT must be freed by calling CertFreeCTLContext. CertDuplicateCTLContext can be called to make a duplicate. CertSetCTLContextProperty and CertGetCTLContextProperty can be called to store and read properties for the CTL.

Example

See CertCreateCertificateContext. In that example, change all references to "certificate" to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertCreateCRLContext, CertCreateCertificateContext


CertDeleteCertificateFromStore

The CertDeleteCertificateFromStore function deletes the specified certificate context from the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertDeleteCertificateFromStore(
  PCCERT_CONTEXT pCertContext         // in
);

Parameters

pCertContext
Pointer to the certificate context.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_ACCESSDENIED | Indicates the store was opened read only and a delete operation is not allowed.

Remarks

All subsequent gets or finds for the certificate will fail. However, memory allocated for the certificate is not freed until all duplicated contexts have also been freed.

The pCertContext is always freed by this function via CertFreeCertificateContext, even for an error.

Example

// handle_error() is a function defined in a separate file.
HANDLE          hStoreHandle;
PCCERT_CONTEXT  pCertContext;

// Open a certificate store and get the PCCERT_CONTEXT of a certificate context.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The MY store is open. Continue.\n");
else
handle_error("The My store did not open.");
// Find the first certificate in the system store.
if(pCertContext= CertEnumCertificatesInStore(
hStoreHandle,NULL))
printf("A certificate has been retrieved. Continue.\n");
else
handle_error("No certificate retrieved. The store may be empty.");
// Delete the certificate.
if(CertDeleteCertificateFromStore(
pCertContext   // The certificate context to be deleted.
   ))
printf("The certificate has been deleted. Continue. \n");
else
// The delete failed. Exit to the error handler.
handle_error("The deletion of the certificate failed.");
// To show that the certificate has been deleted,
// pCertContext is re-added to the certificate store.
if(CertAddCertificateContextToStore(
hStoreHandle,pCertContext,CERT_STORE_ADD_NEW,NULL))
// The context was added showing it was not there
printf("Context added. The delete functioned correctly. \n");
else
    //
// The context could not be added. The cert had not been
// deleted; therefore, the cert to be added was a duplicate.
    //
printf("The cert could not be added. It is a duplicate. \n");
printf("The program ran to completion successfully. \n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertDeleteCRLFromStore


CertDeleteCRLFromStore

The CertDeleteCRLFromStore function deletes the specified CRL context from the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertDeleteCRLFromStore(
  PCCRL_CONTEXT pCrlContext           // in
);

Parameters

pCrlContext
A pointer to the CRL context.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_ACCESSDENIED | Indicates the store was opened read-only and a delete operation is not allowed.

Remarks

All subsequent gets or finds for the CRL will fail. However, memory allocated for the CRL isn't freed until all duplicated contexts have also been freed.

The pCrlContext is always freed by this function via CertFreeCRLContext, even for an error.

Example

See CertDeleteCertificateFromStore. In that example, change all references to "certificate" to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertDeleteCertificateFromStore


CertDeleteCTLFromStore

The CertDeleteCTLFromStore function deletes the specified CTL context from the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertDeleteCTLFromStore(
  PCCTL_CONTEXT pCtlContext           // in
);

Parameters

pCtlContext
Pointer to the CTL context.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_ACCESSDENIED | Indicates the store was opened read-only and a delete operation is not allowed.

Remarks

All subsequent gets or finds for the CTL will fail. However, memory allocated for the CTL isn't freed until all duplicated contexts have also been freed.

The pCtlContext is always freed by this function via CertFreeCTLContext, even for an error.

Example

See CertDeleteCertificateFromStore. In that example, change all references to "certificate" to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertDuplicateCertificateContext

The CertDuplicateCertificateContext function duplicates a certificate context by incrementing the reference count. The reference count is used to keep track of the lifetime of the context.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
  PCCERT_CONTEXT pCertContext          // in
);

Parameters

pCertContext
Pointer to the certificate context for which the reference count is being incremented.

Return Values

Currently, a copy is not made of the context, and the returned context is the same as the context that was input.

Example

// handle_error() is a function defined in a separate file.
HANDLE          hStoreHandle;
PCCERT_CONTEXT  pCertContext;
PCCERT_CONTEXT  pDupCertContext;

// Open a certificate store. For details, see CertOpenStore.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The MY store is open. Continue. \n");
else
handle_error("The store did not open.");
// Get the first certificate in the system store.
if(pCertContext= CertEnumCertificatesInStore(
hStoreHandle,NULL)))
printf("A certificate has been retrieved. Continue. \n");
else
handle_error("Certificate not retrieved. The store may be empty.");
// Close the certificate store. For details, see CertCloseStore.
if(CertCloseStore(hStoreHandle,CERT_CLOSE_STORE_CHECK_FLAG))
// If the function returns TRUE, no certificates remained open.
printf("The store was closed and no certs are still open.\n");
else
// The function returned FALSE. The store is closed, but
// certificates remain open.
printf("Certificates remain open.\n");
// Create a duplicate of the certificate
if(pDupCertContext = CertDuplicateCertificateContext(
pCertContext         //   The certificate to be duplicated.
   ))
printf("A duplicate was created. Continue. \n");
else
handle_error("Duplication of the certificate failed.");
// Use the certificate contexts as necessary.
//   ....
// Free the duplicate certificate.
if(CertFreeCertificateContext(pDupCertContext))
printf("CertDuplicateCertificateContext succeeded. Continue.\n");
else
handle_error("The duplicate cert could not be freed.");
// Free the original certificate.
if(!(CertFreeCertificateContext(pCertContext)))
handle_error("The original certificate was not freed.");
if(!(CertCloseStore(hStoreHandle,0)))
handle_error("The certificate store was not closed.");
printf("The program terminated normally.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertDuplicateCRLContext


CertDuplicateCRLContext

The CertDuplicateCRLContext function duplicates a CRL context by incrementing the reference count. The reference count is used to keep track of the lifetime of the context.

#include <wincrypt.h>
PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(
  PCCRL_CONTEXT pCrlContext            // in
);

Parameters

pCrlContext
Pointer to the CRL context for which the reference count is being incremented.

Return Values

Currently, a copy is not made of the context, and the returned context is the same as the context that was input.

Example

See CertDuplicateCertificateContext. In that example, change all references to "certificate" to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertDuplicateCertificateContext


CertDuplicateCTLContext

The CertDuplicateCTLContext function duplicates a CTL context by incrementing the reference count. The reference count is used to keep track of the lifetime of the context.

#include <wincrypt.h>
PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(
  PCCTL_CONTEXT pCtlContext        // in
);

Parameters

pCtlContext
Pointer to the CTL context for which the reference count is being incremented.

Return Values

Currently, a copy is not made of the context, and the returned context is the same as the context that was input.

Example

See CertDuplicateCertificateContext. In that example, change all references to "certificate" to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertDuplicateStore

The CertDuplicateStore function duplicates a store handle by incrementing the reference count. The reference count is used to keep track of the lifetime of the store.

#include <wincrypt.h>
HCERTSTORE WINAPI CertDuplicateStore(
  HCERTSTORE hCertStore           // in
);

Parameters

hCertStore
Handle to the certificate store for which the reference count is being incremented.

Return Values

Currently, a copy is not made of the handle, and the returned handle is the same as the handle that was input.

Example

// handle_error() is a function defined in a separate file.
HCERTSTORE            hCertStore;    // The store to be duplicated.
HCERTSTORE            hDupStore ;    // The duplicate store to be.

// Open a file store as the certificate store to be duplicated.
// See CertOpenStore for details.
if (hCertStore = CertOpenStore(
CERT_STORE_PROV_FILENAME,0,NULL,0,L"teststor.sto"))
printf("The file store is open. Continue. \n");
else
handle_error("Store not opened");
// Duplicate the store.
if(hDupStore = CertDuplicateStore(hCertStore))
printf("The store is duplicated. Continue.\n");
else
handle_error("Duplication of the store failed.");
if (CertCloseStore(hDupStore,0))
printf("Closed the duplicate store.\n");
else
handle_error("Closing the duplicate store failed.");
if (CertCloseStore(hCertStore,0))
printf("Closed the original store.\n");
else
handle_error("Closing the original store failed.");
printf("Program completed successfully.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertEnumCertificateContextProperties

The CertEnumCertificateContextProperties function enumerates the properties for the specified certificate context.

#include <wincrypt.h>
DWORD WINAPI CertEnumCertificateContextProperties(
  PCCERT_CONTEXT pCertContext,  // in
  DWORD dwPropId                // in
);

Parameters

pCertContext
Pointer to the specified certificate context.
dwPropId
To get the first property, set dwPropId to 0. The ID of the first property is returned. To get the next property, set dwPropId to the ID returned by the last call. To enumerate all the properties, continue enumerating them until 0 is returned.

For any given dwPropId returned, an application may call CertGetCertificateContextProperty to get that property's data.

Return Values

The return value is described under dwPropId in the preceding text.

Call GetLastError to see the reason for any failures.

Remarks

Since the CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_SPEC_PROP_ID properties are stored as fields in the CERT_KEY_CONTEXT_PROP_ID property, they aren't enumerated individually.

Example

//
// Enumerate (List) the property id numbers of a certificate context
// using CertEnumCertificateContextProperties.
//
// handle_error() is a function defined in a separate file.
//
HANDLE           hCertStore;
PCCERT_CONTEXT   pCertContext;
void*            pvData;
DWORD            cbData;
DWORD            dwPropId = 0;   // 0 must be used on the first
                                 // call to the function. After that,
                                 // the last returned property id is passed.

// Open a file based certificate store.
// For details, see CertOpenStore.
if (hCertStore = CertOpenStore(
CERT_STORE_PROV_FILENAME,0,NULL,0,L"TESTSTOR.STO"))
printf("The file store is open. Continue.\n");
else
handle_error("The file based store did not open.");
// Get a certificate from the open store.
if(pCertContext= CertEnumCertificatesInStore(
hCertStore,NULL))
printf("A certificate has been retrieved. Continue. \n");
else
handle_error("No certificate retrieved. The store may be empty.");
// In a loop, find all of the property IDs for the given certificate.
// The loop continues until the function returns a 0.
while(dwPropId = CertEnumCertificateContextProperties(
pCertContext, // the context whose properties are to be listed.
       dwPropId))    // number of the last property found. Must be
                     // 0 to find the first property id.
{
   //
// When the loop is executed, a property id has been found.
// Retrieve information on that property by first getting its size
// For details, see CertGetCertificateContextProperty.
   //
if(CertGetCertificateContextProperty
(pCertContext, dwPropId , NULL, &cbData))
printf("Call #1 succeeded. Continue. \n");
else
handle_error("Call #1 to the function failed.");
// Allocate memory.
if(pvData = (void*)malloc(cbData))
printf("Allocation succeeded. Retrieve the property data.\n");
else
handle_error("Memory allocation failed.");\
if(CertGetCertificateContextProperty(
pCertContext,dwPropId,pvData, &cbData))
printf("The function succeeded. Continue.\n");
else
handle_error("Call #2 to the function failed.\n");
// Show the results
printf("Length %d  \n",cbData);
printf("The Content of pbData is %d \n", pvData);
// Free the certificate context property memory when finished with it.
free(pvData);
} // end while

// Free the certificate context.
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore,0);
printf("The function completed successfully. \n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertEnumCertificatesInStore

The CertEnumCertificatesInStore function enumerates all the certificate contexts in the store.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(
  HCERTSTORE hCertStore               // in
  PCCERT_CONTEXT pPrevCertContext     // in
);

Parameters

hCertStore
Handle to the certificate store.
pPrevCertContext
Pointer to the previous certificate context found. For more details, see the Remarks section.

Return Values

The function returns a pointer to the next CERT_CONTEXT in the store. If no more certificates exist in the store, it returns NULL.

GetLastError may be called to indicate the reason for any failure. This function uses the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument is not the same as the hCertStore of the certificate context pointed to by pPrevCertContext.
CRYPT_E_NOT_FOUND | No certificates were found. This happens if the store is empty or if the function reached the end of the store's list.

Remarks

The pPrevCertContext parameter must be NULL to get the first certificate in the store. Successive certificates are enumerated by setting pPrevCertContext to the pointer returned by a previous call to the function. The enumeration skips any CTLs previously deleted by CertDeleteCertificateFromStore.

The returned pointer is freed when passed as the pPrevCertContext on a subsequent call. Otherwise, the pointer must be freed by calling CertFreeCertificateContext. A pPrevCertContext that is not NULL is always freed by this function even for an error.

A duplicate of the currently enumerated certificate can be made by calling CertDuplicateCertificateContext.

Example

// List the certificates in a store using CertEnumCertificatesInStore
HCERTSTORE             hCertStore;
PCCERT_CONTEXT          pCertContext = NULL;
int                    i=0;
//
// Open a file based certificate store.
// For details, see CertOpenStore.
//
if (hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The file based store is open. Continue.\n");
else
handle_error("The store did not open.");
// In a loop, retrieve each of the certificates in the store.
while(pCertContext= CertEnumCertificatesInStore(
   hCertStore,        // The certificate store being enumerated.
   pCertContext))     // The previous certificate. Must be NULL
                      // for the first call to the function.
printf("%d Another certificate found.\n",++i);
//
// At the end of the loop, print a completion message.
printf("\n\nAll certificates in the store have been enumerated.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindCertificateInStore, CertFindCRLInStore, CertFindCTLInStore


CertEnumCRLContextProperties

The CertEnumCRLContextProperties function enumerates the properties for the specified CRL context.

#include <wincrypt.h>
DWORD WINAPI CertEnumCRLContextProperties(
  PCCRL_CONTEXT pCrlContext,      // in
  DWORD dwPropId                  // in
);

Parameters

pCrlContext
Pointer to the specified CRL context.
dwPropId
To get the first property, set dwPropId to 0. The ID of the first property is returned. To get the next property, set dwPropId to the ID returned by the last call. To enumerate all the properties, continue enumerating them until 0 is returned.

For any given dwPropId returned, an application may call CertGetCRLContextProperty to get that property's data.

Return Values

The return value is described under dwPropId above.

Call GetLastError to see the reason for any failures.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertEnumCRLsInStore

The CertEnumCRLsInStore function enumerates the CRL contexts in a certificate store.

#include <wincrypt.h>
PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(
  HCERTSTORE hCertStore,            // in
  PCCRL_CONTEXT pPrevCrlContext     // in
);

Parameters

hCertStore
Handle to the certificate store.
pPrevCrlContext
Pointer to the previous CRL context found. For more details, see the Remarks section.

Return Values

The function returns a pointer to the next CRL_CONTEXT in the store. If there are no more CRLs in the store, NULL is returned.

GetLastError may be called to indicate the reason for any failure. This function uses the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument is not the same as the hCertStore of the certificate context pointed to by pPrevCertContext.
CRYPT_E_NOT_FOUND | No CRL was found. This happens if the store is empty or the end of the store's list is reached.

Remarks

The pPrevCrlContext parameter must be NULL to get the first CRL in the store. Successive CRLs are enumerated by setting pPrevCRlContext to the the pointer by a previous call to the function. The enumeration skips any certificates previously deleted by CertDeleteCRLFromStore.

The returned pointer is freed when it is passed as the pPrevCrlContext on a subsequent call the function. Otherwise, the pointer must be freed by calling CertFreeCRLContext. A pPrevCrlContext that is not NULL is always freed when passed to this function through a call to CertFreeCRLContext even if the function, itself, returns an error.

A duplicate of the CRL contest returned by this function can be made by calling CertDuplicateCRLContext.

Example

See CertEnumCertificatesInStore. Change all references to "certificate" in that example to "CRL."

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindCRLInStore


CertEnumCTLContextProperties

The CertEnumCTLContextProperties function enumerates the properties for the specified CTL context.

#include <wincrypt.h>
DWORD WINAPI CertEnumCTLContextProperties(
  PCCTL_CONTEXT pCtlContext,     // in
  DWORD dwPropId                 // in
);

Parameters

pCtlContext
Pointer to the specified CTL context.
dwPropId
To get the first property, set dwPropId to 0. The ID of the first property is returned. To get the next property, set dwPropId to the ID returned by the last call. To enumerate all the properties, continue enumerating them until 0 is returned.

For any given dwPropId returned, an application may call CertGetCTLContextProperty to get that property's data.

Return Values

The return value is described under dwPropId above.

Call GetLastError to see the reason for any failures.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertEnumCTLsInStore

The CertEnumCTLsInStore function enumerates all the CTL contexts in the store.

#include <wincrypt.h>
PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(
  HCERTSTORE hCertStore,         // in
  PCCTL_CONTEXT pPrevCtlContext  // in
);

Parameters

hCertStore
Handle to the certificate store.
pPrevCtlContext
Pointer to the previous CTL context found. For more details, see the Remarks section.

Return Values

If a CTL is not found, returns NULL. Otherwise, the function returns a pointer to a read-only CTL_CONTEXT.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument isn't the same as the hCertStore in the CTL context pointed to by the pPrevCtlContext argument.
CRYPT_E_NOT_FOUND | Either no CTLs in the store or reached the end of the store's list.

Remarks

The pPrevCtlContext parameter must be NULL to get the first CTL in the store. Successive CTLs are enumerated by setting pPrevCtlContext to the PCCTL_CONTEXT (the pointer to the constant CTL_CONTEXT) returned by a previous call. The enumeration skips any CTLs previously deleted by CertDeleteCTLFromStore.

The returned pointer is freed when passed as the pPrevCtlContext on a subsequent call. Otherwise, the pointer must be freed by calling CertFreeCTLContext. A pPrevCtlContext that is not NULL is always freed by this function (through a call to CertFreeCTLContext), even for an error.

A duplicate can be made by calling CertDuplicateCTLContext.

Example

See CertEnumCertificatesInStore. Change all references to "certificate" in that example to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindCTLInStore


CertEnumPhysicalStore

[This is preliminary documentation and subject to change.]

The CertEnumPhysicalStore function enumerates the physical stores for a specified system store.

#include <wincrypt.h>
BOOL WINAPI CertEnumPhysicalStore(
  const void pvSystemStore,              // in
  DWORD dwFlags,                         // in
  void *pvArg,                           // in
  PFN_CERT_ENUM_PHYSICAL_STORE pfnEnum   // in
);

Parameters

pvSystemStore
If CERT_SYSTEM_STORE_RELOCATE_FLAG is set in dwFlags, pvSystemStore points to a CERT_SYSTEM_STORE_RELOCATE_PARA that indicates both the name and the location of the system store. Otherwise it is a pointer to a unicode string that names the system store whose physical stores are to be enumerated. See CertRegisterSystemStore for details on prefixing a ServiceName or ComputerName to the system store name.
dwFlags
The HIWORD of the dwFlags parameter specifies the location of the system store.The following dwFlags are defined:
CERT_SYSTEM_STORE_CURRENT_USER
CERT_SYSTEM_STORE_CURRENT_SERVICE
CERT_SYSTEM_STORE_LOCAL_MACHINE
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
CERT_SYSTEM_STORE_CURRENT_MACHINE_GROUP_POLICY
CERT_SYSTEM_STORE_SERVICES
CERT_SYSTEM_STORE_USERS

In addition CERT_SYSTEM_STORE_RELOCATE_FLAG may be ORed with any of the HIWORD location flags.

pvArg
Pointer to a void which allows the application to declare, define, and initialize a data structure to hold any information to be passed to the callback enumeration function.
pfnEnum
Pointer to the callback function used to show the details for each physical store. This callback function determines the content and format for the presentation of information on each physical store. The application must provide the callback function and declare the following signature :
BOOL WINAPI CertEnumPhysicalStoreCallback(
  const void *pvSystemStore,             // in
  DWORD dwFlags,                         // in
  PCERT_SYSTEM_STORE_INFO pStoreInfo,    // in
  void *pvReserved,                      // in, optional
  void *pvArg                            // in, optional
);

The pvArg passed to the callback function is the pvArg pointer passed to CertEnumPhysicalStore.

Return Values

The function returns TRUE if another physical store was found. If another physical store was not found, it returns FALSE.

If the system store location only supports system stores and does not support physical stores, the function returns FALSE and GetLastError returns ERROR_NOT_SUPPORTED.

Remarks

To use CertEnumPhysicalStore, an application must declare and define the ENUM_ARG data structure and an enumeration callback function.

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

See Example Code for Listing System and Physical Stores.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertRegisterPhysicalStore, CertUnregisterSystemStore, CertUnregisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumSystemStore


CertEnumSubjectInSortedCTL

[This is preliminary documentation and subject to change.]

The CertEnumSubjectInSortedCTL function enumerates through the TrustedSubjects in a sorted CTL context (a CTL context created with CERT_CREATE_CONTEXT_SORTED_FLAG set). A FALSE is returned for the last subject in the sorted CTL.

#include <wincrypt.h>
BOOL WINAPI CertEnumSubjectInSortedCTL(
  PCCTL_CONTEXT pCtlContext,           //  in
  void **ppvNextSubject,               //  in, out
  PCRYPT_DER_BLOB pSubjectIdentifier,  //  out, optional
  PCRYPT_DER_BLOB pEncodedAttributes   //  out, optional
);

Parameters

pCtlContext
Pointer to the CTL_CONTEXT to be searched.
ppvNextSubject
Pointer to the address of the next TrustedSubject. To start the enumeration, *ppvNextSubject must be NULL. Upon return, *ppvNextSubject is updated to point to the next TrustedSubject in the encoded sequence.
pSubjectIdentifier
Pointer to a CRYPT_DER_BLOB structure, uniquely identifying a TrustedSubject. It can be a hash or any unique byte sequence. See BLOB Structure.
pEncodedAttributes
Pointer to a CRYPT_DER_BLOB structure containing a byte count and a pointer to the TrustedSubject's encoded attributes. See BLOB Structure.

Return Values

TRUE with *ppvNextSubject updated to point to the next TrustedSubject in the encoded sequence. FALSE if there are no more subjects or there is an invalid argument.

Remarks

The returned CRYPT_DER_BLOB structures point directly into the encoded bytes. They are not allocated, and therefore must not be freed.

If the CTL is not sorted with the CERT_CREATE_CONTEXT_SORTED_FLAG flag set, an error will result.

To retrieve extended error information, use the GetLastError function.

Example

// EXAMPLE CODE FOR USING CertEnumSubjectInSortedCTL().
// Assume a pointer to the CTL_CONTEXT (pCtlContext) is initialized
// elsewhere.
// Declare and initialize
int count= 0;                       // Counter
PCCTL_CONTEXT pCtlContext;          // Initialized elsewhere
void **ppvNextSubject;              // Pointer to the address of the
                                    //  next subject. NULL to start
                                    //  the enumeration.
CRYPT_DER_BLOB SubjectIdentifier;   // Pointer to a BLOB structure
                                    //   identifiable to the subject.
CRYPT_DER_BLOB EncodedAttributes;   // Pointer to the BLOB structure
                                    //   attributes.
BOOL fResult;                       // Returns TRUE if the function
                                    //   finds a TrustedSubject. FALSE
                                    //   if the last TrustedSubject
                                    //   has been found.

// Function call to CertEnumSubjectInSortedCTL().
ppvNextSubject= NULL;               // NULL to start the enumeration.
do {
fResult= CertEnumSubjectInSortedCTL(
              pCtlContext,          // in- Pointer to the CTL_CONTEXT
                                    //   to be searched.
              ppvNextSubject,       // in, out- NULL for the first
                                    //   function call.
              &SubjectIdentifier,   // out, optional- Pointer to
                                    //   unique BLOB structure.
&EncodedAttributes);                // out, optional- Pointer to
//   attributes BLOB structure.
if(fResult)
{  // TRUE returned- The subject was found.
// Now print out and search again.
count++;                    // Increment counter.
printf("%d. Subject found in sorted CTL.\n", count);
printf("%d. ppvNextSubject is reset to %d.\n", count,
ppvNextSubject);
    }
} while (fResult);                  //   Keep looping through the CTL
                                    //   until the last TrustedSubject
                                    //   is found.

// FALSE returned- function at the end of the CTL.
printf("CertEnumSubjectInSortedCTL enumeration complete.\n");
printf("There are %d TrustedSubjects in the CTL.\n", count);
if (!count) { // Count =0- This is an empty CTL or an error occurred.
printf("No TrustedSubject found. Check for errors.\n");
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindSubjectInSortedCTL


CertEnumSystemStore

[This is preliminary documentation and subject to change.]

The CertEnumSystemStore function enumerates all available system stores.

#include wincrypt.h
BOOL WINAPI CertEnumSystemStore(
  DWORD dwFlags,                         // in
  void *pvSystemStoreLocationPara,       // in optional
  void *pvArg,                           // in
  PFN_CERT_ENUM_SYSTEM_STORE pfnEnum     // in
);

Parameters

dwflags
Specifies the location of the system store. The following dwFlags are defined:

CERT_SYSTEM_STORE_CURRENT_USER
CERT_SYSTEM_STORE_CURRENT_SERVICE
CERT_SYSTEM_STORE_LOCAL_MACHINE
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY
CERT_SYSTEM_STORE_CURRENT_MACHINE_GROUP_POLICY
CERT_SYSTEM_STORE_SERVICES
CERT_SYSTEM_STORE_USERS

In addition CERT_SYSTEM_STORE_RELOCATE_FLAG may be combined with any location flags using a bitwise OR.

pvSystemStoreLocationPara
If CERT_SYSTEM_STORE_RELOCATE_FLAG is set in dwFlags, pvSystemStore points to a CERT_SYSTEM_STORE_RELOCATE_PARA that indicates both the name and the location of the system store. Otherwise it is a pointer to a unicode string that names the system store.

For CERT_SYSTEM_STORE_LOCAL_MACHINE or CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY, pvSystemStoreLocationPara can optionally be set to a unicode computer name for enumerating local machine stores on a remote computer. For example, "\\ComputerName" or "ComputerName". The leading "\\" backslashes are optional in the ComputerName.

For CERT_SYSTEM_STORE_SERVICES or CERT_SYSTEM_STORE_USERS, if pvSystemStoreLocationPara is NULL, then, the function enumerates both the service/user names and the stores for each service/user name. Otherwise, pvSystemStoreLocationPara is a unicode string specifying a remote computer name and/or service/user name. For example: "ServiceName,""\\ComputerName," or "ComputerName\"

If only the ComputerName is specified, it must have either the leading "\\" backslashes or a trailing backslash. Otherwise, it is interpreted as the ServiceName or UserName.

pvArg
Pointer to a void which allows the application to declare, define, and initialize a data structure to hold any information to be passed to the callback enumeration function.
pfnEnum
Pointer to the callback function used to show the details for each system store. This callback function determines the content and format for the presentation of information on each system store. The application must provide the callback function and must declare it with the following signature :
BOOL  WINAPI CertEnumSystemStoreCallback(
  const void *pvSystemStore,           // in
  DWORD dwFlags,                       // in
  PCERT_SYSTEM_STORE_INFO pStoreInfo,  // in
  void *pvReserved,                    // in, optional
  void *pvArg                          // in, optional
);

The pvArg passed by CertEnumSystemStore to the callback function is the pvArg pointer passed to CertEnumSystemStore.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Remarks

To use CertEnumSystemStore, the application must declare and define the ENUM_ARG data structure and an enumeration callback function.

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

See Example Code for Listing System and Physical Stores.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertRegisterPhysicalStore, CertUnregisterSystemStore, CertUnregisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumPhysicalStore


CertEnumSystemStoreLocation

[This is preliminary documentation and subject to change.]

The CertEnumSystemStoreLocation function enumerates all of the locations that have an available system store.

#include <wincrypt.h>
BOOL WINAPI CertEnumSystemStoreLocation(
  DWORD dwFlags,                               //in
  void *pvArg,                                 //in
  PFN_CERT_ENUM_SYSTEM_STORE_LOCATION pfnEnum  //in
);

Parameters

dwFlags
The HIWORD of the dwFlags is not used and must be set to 0.
pvArg
Pointer to a void which allows the application to declare, define, and initialize a data structure to hold any information to be passed to the callback enumeration function.
pfnEnum
Pointer to the callback function used to show the details for each store location. This callback function determines the content and format for the presentation of information on each store location. The callback function must be provided by the application and must be declared with the following signature:
BOOL  WINAPI CertEnumStoreLocationCallback(
  const void *pvSystemStore,           // in
  DWORD dwFlags,                       // in
  PCERT_SYSTEM_STORE_INFO pStoreInfo,  // in
  void *pvReserved,                    // in, optional
  void *pvArg                          // in, optional
);

The pvArg passed to the callback function is the pvArg pointer passed to CertEnumSystemStoreLocation.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Remarks

To use CertEnumSystemStoreLocation, an application must declare and define the ENUM_ARG data structure and an enumeration callback function.

Example

See Example Code for Listing System and Physical Stores.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertRegisterPhysicalStore, CertUnregisterSystemStore, CertUnregisterPhysicalStore, CertEnumPhysicalStore, CertEnumSystemStore


CertFindCertificateInStore

[This is preliminary documentation and subject to change.]

The CertFindCertificateInStore function finds in a certificate store the first or next certificate context that matches a search criteria. The search criteria is established by the dwFindType and its associated pvFindPara.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertFindCertificateInStore(
  HCERTSTORE hCertStore,              // in
  DWORD dwCertEncodingType,           // in
  DWORD dwFindFlags,                  // in
  DWORD dwFindType,                   // in
  const void *pvFindPara,             // in
  PCCERT_CONTEXT pPrevCertContext     // in
);

Parameters

hCertStore
Handle of the certificate store to be searched.
dwCertEncodingType
Type of encoding used on the certificate. The LOWORD specifies the encoding type of certificates, CRLs, and CTLs in the cryptographic message. The HIWORD specifies the encoding type of the message.

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

Both a certificate and message encoding type should be specified. This is done by combining them with a bitwise OR operation, as shown in the following example:

X509_ASN_ENCODING | PKCS_7_ASN_ENCODING
dwFindFlags
dwFindFlags values are used with some dwFindTypes to modify the search criteria. For most find types, it is not used and should be set to 0. See the Remarks section for detailed information.
dwFindType
DWORD that determines the type of search being made. The find type used determines the data type, contents, and use of pvFindPara. Currently defined find types and their required data type of pvFindPara are:
dwFindType | pvFindPara
CERT_FIND_ANY | NULL. pvFindPara not used
CERT_FIND_HASH | CRYPT_HASH_BLOB
CERT_FIND_SHA1_HASH | CRYPT_HASH_BLOB
CERT_FIND_MD5_HASH | CRYPT_HASH_BLOB
CERT_FIND_SIGNATURE_HASH | CRYPT_HASH_BLOB
CERT_FIND_PROPERTY | DWORD for the PROP_ID
CERT_FIND_PUBLIC_KEY | CERT_PUBLIC_KEY_INFO
CERT_FIND_SUBJECT_NAME | CERT_NAME_BLOB
CERT_FIND_ISSUER_NAME | CERT_NAME_BLOB
CERT_FIND_SUBJECT_ATTR | CERT_RDN structure
CERT_FIND_ISSUER_ATTR | CERT_RDN structure
CERT_FIND_SUBJECT_STR | NULL terminated wide (unicode) string
CERT_FIND_ISSUER_STR | NULL terminated wide (unicode) string
CERT_FIND_KEY_SPEC | DWORD for dwKeySpec
CERT_FIND_ENHKEY_USAGE | CERT_ENHKEY_USAGE structure
CERT_FIND_SUBJECT_CERT | CERT_INFO structure
CERT_FIND_ISSUER_OF | CERT_CONTEXT structure
CERT_FIND_EXISTING | CERT_CONTEXT structure

Note There are alternate forms of find types that pass a string in pvFindPara. One form uses a unicode string and the other an ASCII string. Find types that end in "_W" or that end without a suffix use unicode. Find types that end with "_A" use ASCII strings.

CERT_FIND_ANY
This find type uses no search criteria and returns the next certificate in the store.
CERT_FIND_HASH and CERT_FIND_SHA1_HASH
These find types are exactly the same. Each searches for a certificate with a SHA1 hash that matches the hash in the CRYPT_HASH_BLOB.
CERT_FIND_MD5_HASH
This find type searches for a certificate with an MD5 hash that matches the hash in the CRYPT_HASH_BLOB.
CERT_FIND_SIGNATURE_HASH
This find type searches for a certificate with a signature hash that matches the signature hash in the CRYPT_HASH_BLOB.
CERT_FIND_PROPERTY
This find type searches for a certificate with a property that matches the property in the PROP_ID identified by the DWORD.
CERT_FIND_PUBLIC_KEY
This find type searches for a certificate with a public key that matches the public key in the CERT_PUBLIC_KEY_INFO.
CERT_FIND_SUBJECT_NAME and CERT_FIND_ISSUER_NAME
These find types search for a certificate with an exact match of the entire subject or issuer name with the name in the CERT_NAME_BLOB. The search is restricted to certificates that match the dwCertEncodingType.
CERT_FIND_SUBJECT_ATTR and CERT_FIND_ISSUER_ATTR
These find types search for a certificate with specified subject or issuer attributes that match an attribute in the CERT_RDN (Relative Distinguished Name). Attributes of the subject or the issuer in a certificate are compared with elements of the CERT_RDN_ATTR array in CERT_RDN. Comparisons iterate through the CERT_RDN_ATTR attributes looking for a match with the certificate's subject or issuer attributes.

If CERT_RDN_ATTR.pszObjId is NULL, the attribute object identifier is ignored.

If CERT_RDN_ATTR.dwValueType is CERT_RDN_ANY_TYPE, the value type is ignored.

If CERT_RDN_VALUE_BLOB.pbData is NULL, any value is a match.

Currently only an exact, case sensitive, match is supported. See the Remarks section for details on unicode options. The search is restricted to certificates matching the dwCertEncodingType.

CERT_FIND_SUBJECT_STR and CERT_FIND_ISSUER_STR
These find types search for a certificate containing the specified subject or issuer name string. The certificate's subject or issuer member is converted to a name string of the appropriate type using the appropriate form of CertNameToStr formatted as CERT_SIMPLE_NAME_STR. Then a case insensitive substring-within-a-string match is performed. The search is restricted to certificates matching the dwCertEncodingType.
CERT_FIND_KEY_SPEC
This find type searches for a certificate having a CERT_KEY_SPEC_PROP_ID property matching the dwKeySpec passed as pvFindPara.
CERT_FIND_ENHKEY_USAGE
Find a certificate in the store having
1. | either the enhanced key usage extension or the enhanced key usage property and
2. | usage identifiers that match the pszUsageIdentifers in the CERT_ENHKEY_USAGE data structure passed as pvFindPara.

A certificate has the enhanced key usage extension if it has a CERT_EXTENSION with pszObjId set to szOID_ENHANCED_KEY_USAGE. It has the enhanced key usage property if its CERT_ENHKEY_USAGE_PROP_ID is set.

The pvFindPara parameter points to a CERT_ENHKEY_USAGE data structure. If pvFindPara is NULL or CERT_ENHKEY_USAGE.cUsageIdentifier is 0, no pszUsageIdentifers need to be matched and any certificate that has either the enhanced key usage extension or the enhanced key usage property meets the selection criteria.

See the Remarks section for details on flag modifications to find criteria.

This find type searches for a certificate having the szOID_ENHANCED_KEY_USAGE extension or the CERT_ENHKEY_USAGE_PROP_ID that matches the pszUsageIdentifer in the CERT_ENHKEY_USAGE structure pointed to by pvFindPara.

If pvFindPara is NULL or the cUsageIdentifier in the CERT_ENHKEY_USAGE structure is 0, any certificate having enhanced key usage is a match.

If CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG is set in dwFindFlags, certificates without the key usage extension or property are also matches.

If CERT_FIND_NO_ENHKEY_USAGE_FLAG is set in dwFindFlags, certificates without the key usage extension or property are found. Setting this flag takes precedence over passing NULL in pvFindPara.

If CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG is set, a match is done only on the extension.

CERT_FIND_CTL_USAGE
This find type searches for a certificate having a szOID_ENHANCED_KEY_USAGE extension or a CERT_CTL_PROP_ID that matchs the pszUsageIdentifier in the CTL_USAGE structure pointed to by pvFindPara.
CERT_FIND_SUBJECT_CERT
This find type searches for a certificate with both an issuer and a serial number that match the issuer and serial number in the CERT_INFO pointed to by pvFindPara.
CERT_FIND_ISSUER_OF
This find type search for a certificate with an issuer that matches the issuer in the CERT_CONTEXT pointed to by pvFindPara.
CERT_FIND_EXISTING
This find type searches for a certificate that is an exact match of the certificate context pointed to by pvFindPara.
pvFindPara
Points to a data item or structure associated with the dwFindType. Information on the type of the information to be passed in pvFindPara can be found in the list under dwFindType.
pPrevCertContext
Pointer to the last CERT_CONTEXT returned by this function. It must be NULL on the first call of the function. A pPrevCertContext that is not NULL is always freed by this even if the function causes an error.

Return Values

If a certificate that matches the search criteria is not found, NULL is returned. Otherwise, a pointer to a read-only CERT_CONTEXT is returned. A non-NULL CERT_CONTEXT returned must be freed by CertFreeCertificateContext or by being passed as pPrevCertContext on a subsequent call to CertFindCertificateInStore.

CertDuplicateCertificateContext can be called to make a duplicate of the returned context. The returned context may be added to a different certificate store using CertAddCertificateContextToStore or a link to that certificate context can be added to a non-collection store using CertAddCertificateLinkToStore

GetLastError may be called to indicate the reason for any failure. This function uses the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument isn't the same as the hCertStore of the certificate context pointed to by the pPrevCertContext argument or an invalid find type specified by dwFindType argument.
CRYPT_E_NOT_FOUND | No certificate was found matching the find criteria. This can happen if the store is empty or the end of the store's list is reached.

Remarks

The dwFindFlags parameter is used to modify the criteria of some search types.

CERT_UNICODE_IS_RDN_ATTRS_FLAG is used only with CERT_FIND_SUBJECT_ATTR and CERT_FIND_ISSUER_ATTR.
This flag must be set if the CERT_RDN_ATTR structure was initialized with UNICODE strings. Before any comparison is made the string to be matched is converted via X509_UNICODE_NAME to provide for unicode comparisons.

The following dwFindFlags are used only with CERT_FIND_ENKEY_USAGE:

CERT_FIND_OR_ENHKEY_USAGE_FLAG
The find criteria can be altered by setting one or more dwFindFlags. By default, if pszUsageIdentifers are to be match, all of those identifiers must be matched to satisfy the search criteria; however, if CERT_FIND_OR_ENHKEY_USAGE_FLAG is set, an "OR" match of any of the specified pszUsageIdentifiers is done and matching any one of the identifiers is sufficient.
CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG
When this flag is set, in addition to normal matches, any certificate that has neither the enhanced key usage extension nor the enhanced key usage property meets the search criteria.
CERT_FIND_NO_ENHKEY_USAGE_FLAG
When this flag is set, only those certificates that have neither an enhanced key usage nor the enhanced key usage property are matches. This flag setting takes precedence over pvFindPara being NULL.
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG
When this flag is set, the matching process involves only the extension usage identifiers. If pvFindPara is NULL or cUsageIdentifier is 0, any certificate having the enhanced key usage extension is a match. If CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG is also set, any certificate without the enhanced key usage extension is also a match. When CERT_FIND_NO_ENHKEY_USAGE_FLAG is also set, only certificates without the enhanced key usage extension are matches.
CERT_FIND_EXT_PROP_ENHKEY_USAGE_FLAG
When this flag is set, the matching process involves only usage identifiers that are properties. If pvFindPara is NULL or cUsageIdentifier is set to 0, any certificate having an enhanced key usage property is a match. If CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG is also set, any certificate without the enhanced key usage property is also a match. If CERT_FIND_NO_ENHKEY_USAGE_FLAG is set, only certificates without the enhanced key usage property are matches.

Example

//
// Find a certificate meeting a specific search critera
// using CertFindCertificateInStore.
// In this case, a search is made for a certificate that has
// has a CERT_HASH_PROP_ID attached.
//
// handle_error() is a function defined in a separate file.
//
HCERTSTORE         hStoreHandle;
PCCERT_CONTEXT     pCertContext = NULL;
DWORD              PropId = CERT_HASH_PROP_ID;
int                i = 0;

// Open a certificate store.
// For details, see CertOpenStore.
if(hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,0,NULL,CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The MY store is open. Continue.\n");
else
handle_error("The store did not open.");
//
// Find all of the certificates in the store meeting the search
// criteria. In this case, in a loop find all certificates
// that have the CERT_HASH_PROP_ID property.
while ((pCertContext= CertFindCertificateInStore(
 hStoreHandle,         // Handle of the store to be searched.
 0,                    // Encoding type. Not used for this search.
 0,                    // dwFindFlags. Special find criteria.
                       // Not used in this search.
 CERT_FIND_PROPERTY,   // Find type. Determines the kind of search
                       // to be done. In this case, search for
                       // certificates that have a specific
                       // extended property.
 &PropId,              // pvFindPara. Gives the specific
                       // value searched for, here, the id of an
                       // extented property.
 pCertContext)))       // pCertContext is NULL for the
                       // first call to the function.
                       // If the function were being called
                       // in a loop, after the first call,
                       // pCertContext would be the cert
                       // returned by the previous call.
printf("Certificate %d has been retrieved.\n",++i);
//
// After the while loop, print a completion message.
printf("The process ran to completion with no errors.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertEnumCertificatesInStore


CertFindCRLInStore

[This is preliminary documentation and subject to change.]

The CertFindCRLInStore function finds in a certificate store the first or next CRL that matches a search criteria. The search criteria is established by the dwFindType and its associated pvFindPara.

#include <wincrypt.h>
PCCTL_CONTEXT WINAPI CertFindCRLInStore(
  HCERTSTORE hCertStore,                  // in
  DWORD dwMsgAndCertEncodingType,         // in
  DWORD dwFindFlags,                      // in
  DWORD dwFindType,                       // in
  const void *pvFindPara,                 // in
  PCCRL_CONTEXT pPrevCRLContext           // in
);

Parameters

hCertStore
Handle to the certificate store to be searched.
dwMsgAndCertEncodingType
Currently not used. It should be set to 0
dwFindFlags
Currently not used. It should be set to 0.
dwFindType
DWORD that establishes the type of search being made. The value of dwFindType determines the data type, contents, and use of the pvFindPara parameter. Currently defined find types and their pvFindPara requirements are:
dwFindType | pvFindPara
CRL_FIND_ANY | not used. Should be set to NULL
CRL_FIND_ISSUED_BY | PCCERT_CONTEXT
CRL_FIND_EXISTING | PCCRL_CONTEXT

CRL_FIND_ANY uses no special search criteria. The next CRL in the store is returned.

CRL_FIND_ISSUED_BY searches for the next CRL in the store matching the issuer in the PCCERT_CONTEXT passed in pvFindPara.

CRL_FIND_EXISTING searches for a CRL that is an exact match of the CRL in the PCCRL_CONTEXT pointed to by pvFindPara.

pvFindPara
NULL for CRL_FIND_ANY or a PCERT_CONTEXT for CRL_FIND_ISSUED_BY, or PCCRL_CONTEXT for CRL_FIND_EXISTING.
pPrevCRLContext
Pointer to the last CRL_CONTEXT returned by this function. It must be NULL on the first call of the function. A pPrevCrlContext that is not NULL is always freed by this even if the function causes an error.

Return Values

Pointer to a read-only CRL context is returned. The returned CRL context must be freed by calling CertFreeCRLContext or be implicitly freed when passed as the pPrevCrlContext parameter on a subsequent call to CertFindCRLInStore. If a CRL that matches the search criteria is not found, NULL is returned.

CertDuplicateCRLContext can be called to make a duplicate of the returned context. The returned CRL context may be added to a different certificate store using CertAddCRLContextToStore or a link to that CRL context can be added to a non-collection store using CertAddCRLLinkToStore.

Call GetLastError for the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument isn't the same as the hCertStore in the CRL context pointed to by the pPrevCtlContext argument. Invalid find type specified by dwFindType argument.
CRYPT_E_NOT_FOUND | No CRLs are in the store, or no CRL was found matching the find criteria, or reached the end of the store's list.

Remarks

The pPrevCRLContext parameter must be NULL to get the first CRL in the store that meets the search criteria. Successive CRLs that meet the find criteria can be found by setting pPrevCRLContext to the PCCRL_CONTEXT pointer returned by a previous call to the function. The find process skips any CRLs that do not match the find criteria or that have been previously deleted by CertDeleteCRLFromStore.

The returned pointer is freed when passed as the pPrevCRLContext parameter on a subsequent call to the function. Otherwise, the pointer must be freed by calling CertFreeCRLContext. A pPrevCRLContext that is not NULL is always freed by this function via a call to CertFreeCRLContext even if there is an error in the function.

Example

See CertFindCertificateInStore. All references to "certificate" should be changed to "CRL."

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertFindCTLInStore

[This is preliminary documentation and subject to change.]

The CertFindCTLInStore function finds the first or next CTL that matches a search criteria. The search criteria is established by the dwFindType and its associated pvFindPara.

#include <wincrypt.h>
PCCTL_CONTEXT WINAPI CertFindCTLInStore(
  HCERTSTORE hCertStore,                  // in
  DWORD dwMsgAndCertEncodingType,         // in
  DWORD dwFindFlags,                      // in
  DWORD dwFindType,                       // in
  const void *pvFindPara,                 // in
  PCCTL_CONTEXT pPrevCtlContext           // in
);

Parameters

hCertStore
Handle to the certificate store to be searched.
dwMsgAndCertEncodingType
Type of encoding used on the CTL. This parameter is used only with the CTL_FIND_USAGE find type and only the LOWORD specifying the encoding type for a signer is needed. For that find type, the parameter should be set to X509_ASN_ENCODING.
dwFindFlags
dwfindFlags can be set for dwfindtype CTL_FIND_USAGE. See the comments under CTL_FIND_USAGE for details.
dwFindType
DWORD that establishes the search type. The value of dwFindType determines the data type, contents, and use of the pvFindPara parameter. Currently defined find types and their pvFindPara requirements are:
CTL_FIND_ANY
pvFindPara is not used. Any CTL is a match.
CTL_FIND_SHA1_HASH or CTL_FIND_MD5_HASH
pvFindPara points to a CRYPT_HASH_BLOB. A CTL with the a hash matching the hash in the CRYPT_HASH_BLOB is found.
CTL_FIND_USAGE
Finds a CTL having a usage identifier, list identifier, or signer matching the usage identifier, list identifier, or signer in the CTL_FIND_USAGE_PARA pointed to by pvFindPara.

If the SubjectUsage.cUsageIdentifier in the CTL_FIND_USAGE_PARA is 0, any CTL is a match.

If the ListIdentifier.cbData in the CTL_FIND_USAGE_PARA is 0, any list identifier is a match. If ListIdentifier.cbData is CTL_FIND_NO_LIST_ID_CBDATA, only a CTL without a list identifier is a match.

If pSigner in the CTL_FIND_USAGE_PARA is NULL, any CTL signer is a match and only the Issuer and SerialNumber fields in the pSigner's PCERT_INFO are used. If psigner is CTL_FIND_NO_SIGNER_PTR, only a CTL without a signer is a match.

CTL_FIND_SAME_USAGE_FLAG
Match only CTLs with the exact same usage identifiers. CTLs having additional usage identifiers are not matched. For example, if only "1.2.3" is specified in CTL_FIND_USAGE_PARA, then, for a match, the CTL must only contain "1.2.3" and no additional usage identifiers.
CTL_FIND_SUBJECT
pvFindPara points to a CTL_FIND_SUBJECT_PARA data structure. A CTL having the specified subject is found. CertFindSubjectInCTL can be called to get a pointer to the subject's entry in the CTL. pUsagePara in CTL_FIND_SUBJECT_PARA can optionally be set to enable the above CTL_FIND_USAGE matching.
pvFindPara
Points to the find parameter associated with the dwFindType.
pPrevCtlContext
Pointer to the last CTL_CONTEXT returned by this function. It must be NULL on the first call of the function. A pPrevCtlContext that is not NULL is always freed by this even if the function causes an error.

Return Values

A pointer to a read-only CTL context is returned. The CTL context must be freed by calling CertFreeCTLContext or it is implicitly freed when passed as the pPrevCtlContext on a subsequent call to CertFindCTLInStore. CertDuplicateCTLContext can be called to make a duplicate of the returned context. The returned CTL context may be added to a different certificate store using CertAddCTLContextToStore or a link to that CTL context can be added to a non-collection store using CertAddCTLLinkToStore. If a CTL matching the search criteria is not found, NULL is returned.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument isn't the same as the hCertStore in the CTL context pointed to by the pPrevCtlContext argument. Invalid find type specified by dwFindType argument.
CRYPT_E_NOT_FOUND | No CTLs in the store, or no CTL was found matching the find criteria, or reached the end of the store's list.

Remarks

The pPrevtrlContext parameter must be NULL to get the first CTL in the store. Successive CTLs that match the find criteria are retrieved by setting pPrevCTlContext to the pointer to the CTL_CONTEXT returned by a previous function call. Any certificates that do not meet the find criteria or that have been previously deleted by CertDeleteCTLFromStore. are skipped.

A returned pointer is freed when passed as the pPrevCtlContext on a subsequent call to the function. Otherwise, the pointer must be freed by calling CertFreeCTLContext. A non-NULL pPrevCtlContext passed to the function is always freed with a call to CertFreeCTLContext even if the function generates an error.

Example

See CertFindCertificateInStore. All references to "certificate" should be changed to "CTL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertEnumCTLsInStore


CertFindSubjectInSortedCTL

[This is preliminary documentation and subject to change.]

The CertFindSubjectInSortedCTL function attempts to find the specified subject in a sorted CTL.

#include <wincrypt.h>
BOOL WINAPI CertFindSubjectInSortedCTL(
  PCRYPT_DATA_BLOB pSubjectIdentifier,  // in
  PCCTL_CONTEXT pCtlContext,            // in
  DWORD dwFlags,                        // in
  void *pvReserved,                     // in
  PCRYPT_DER_BLOB pEncodedAttributes    // out, optional
);

Parameters

pSubjectIdentifier
Pointer to a CRYPT_DATA_BLOB structure uniquely identifying the subject. It can be a hash or any unique byte sequence. See BLOB Structure.
pCtlContext
Pointer to the CTL_CONTEXT to be searched.
dwFlags
Flag values.

This parameter is reserved for future use and should always be zero.

pvReserved
This parameter is reserved for future use and must be NULL.
pEncodedAttributes
Pointer to a CRYPT_DER_BLOB structure containing a byte count and a pointer to the Subject's encoded attributes. See BLOB Structure.

Return Values

TRUE if the SubjectIdentifier exists in the CTL, FALSE if the function does not locate a matching SubjectIdentifier.

Example

// EXAMPLE CODE FOR USING CertFindSubjectInSortedCTL().
// Assume pointers to the Subject Blob (pSubjectIdentifier) and
// the PCCTL_CONTEXT (pCtlContext) are initialized elsewhere.
// Declare and initialize.
PCRYPT_DER_BLOB pSubjectIdentifier;
// Pointer to a BLOB structure
                                //   identifiable to the subject.
                                //   Initialized elsewhere
PCCTL_CONTEXT pCtlContext;      // Pointer to a CTL context.
                                //   Initialized elsewhere
CRYPT_DER_BLOB EncodedAttributes;
// Pointer to a BLOB struture
                                //   containing the found Subject's
                                //   encoded attributes.
BOOL fResult;                   // Returns TRUE if function finds a
                                //   SubjectIdentifier in the CTL.
                                //   FALSE if the SubjectIdentifier is
                                //   not found.
// Function call to CertFindSubjectInSortedCTL().
fResult= CertFindSubjectInSortedCTL(
          pSubjectIdentifier,   // in- Pointer to a BLOB struture,
                                //   identifying the subject.
          pCtlContext,          // in- Pointer to the CTL_CONTEXT
                                //   to be searched.
          0,                    // in- dwFlags- reserved, set to 0
          NULL,                 // in- pvReserved- reserved, set to
                                //   NULL
&EncodedAttributes);            // out, optional- Pointer to
//   attributes BLOB structure
if(fResult){  // TRUE returned- the subject was found in the CTL.
printf("The subject was found in the sorted CTL.\n");
    }
else {        // FALSE returned- the subject was not found in the CTL.
printf("The subject was not found in the sorted CTL.\n");
    }

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertEnumSubjectInSortedCTL


CertFreeCertificateContext

The CertFreeCertificateContext function frees a certificate context by decrementing its reference count. When the reference count goes to zero, CertFreeCertificateContext frees the memory occupied by a certificate context. Each context obtained by a get, find, enum, duplicate, or create must have a corresponding free.

#include <wincrypt.h>
BOOL WINAPI CertFreeCertificateContext(
  PCCERT_CONTEXT pCertContext         // in
);

Parameters

pCertContext
Pointer to the CERT_CONTEXT that is to be freed.

Return Values

Always returns TRUE.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFreeCRLContext


CertFreeCRLContext

The CertFreeCRLContext function frees a CRL context by decrementing its reference count. When the the reference count goes to zero, CertFreeCRLContext frees the memory occupied by a CRL context. Each context obtained by a get, find, enum, duplicate, or create must have a corresponding free.

#include <wincrypt.h>
BOOL WINAPI CertFreeCRLContext(
  PCCRL_CONTEXT pCrlContext        // in
);

Parameters

pCrlContext
Pointer to the CRL_CONTEXT that is to be freed.

Return Values

Always returns TRUE.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFreeCertificateContext


CertFreeCTLContext

The CertFreeCTLContext function frees a CTL context by decrementing its reference count. When the reference count goes to zero, CertFreeCTLContext frees the memory occupied by a CTL context. Each context obtained by a get, find, enum, duplicate, or create must have a corresponding free.

#include <wincrypt.h>
BOOL WINAPI CertFreeCTLContext(
  PCCTL_CONTEXT pCtlContext           // in
);

Parameters

pCtlContext
Pointer to the CTL_CONTEXT that is to be freed.

Return Values

Always returns TRUE.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFreeCRLContext


CertGetCertificateContextProperty

The CertGetCertificateContextProperty function gets a property of a specified certificate context.

#include <wincrypt.h>
BOOL WINAPI CertGetCertificateContextProperty(
  PCCERT_CONTEXT pCertContext,          // in
  DWORD dwPropId,                       // in
  void *pvData,                         // out
  DWORD *pcbData                        // in/out
);

Parameters

pCertContext
Pointer to the certificate context.
dwPropId
ID for the desired property. Currently defined IDs and the data type to be passed in pvData are listed in the following table.
Property ID | Value pvData type
CERT_KEY_PROV_HANDLE_PROP_ID | HCRYPTPROV
CERT_KEY_PROV_INFO_PROP_ID | CRYPT_KEY_PROV_INFO
CERT_SHA1_HASH_PROP_ID | ARRAY OF BYTES
CERT_MD5_HASH_PROP_ID | ARRAY OF BYTES
CERT_HASH_PROP_ID | ARRAY OF BYTES
CERT_KEY_CONTEXT_PROP_ID | CERT_KEY_CONTEXT
CERT_KEY_SPEC_PROP_ID | DWORD
CERT_ENHKEY_USAGE_PROP_ID | ARRAY OF BYTES
CERT_CTL_USAGE_PROP_ID | CERT_ENHKEY_USAGE_PROP_ID
CERT_FRIENDLY_NAME_PROP_ID | ARRAY OF BYTES
CERT_PVK_FILE_PROP_ID | ARRAY OF BYTES
CERT_SIGNATURE_HASH_PROP_ID | ARRAY OF BYTES
CERT_NEXT_UPDATE_LOCATION_PROP_ID | ARRAY OF BYTES
CERT_ACCESS_STATE_PROP_ID | DWORD

The following list presents the definitions for the dwPropId types:

CERT_KEY_PROV_HANDLE_PROP_ID
The hCryptProv returned in pvdata is obtained from the CERT_KEY_CONTEXT_PROP_ID
CERT_KEY_PROV_INFO_PROP_ID
Values are returned in the CRYPT_KEY_PROV_INFO data structure pointed to by pvData.
CERT_HASH_PROP_ID, CERT_SHA1_HASH_PROP_ID or CERT_MD5_HASH_PROP_ID
If the hash does not exist, it is computed using CryptHashCertificate. The existing or computed hash is pointed to by pvData. The length of the hash is 20 bytes for SHA1 and 16 bytes for MD5. If no hCryptProv was specified when the store was opened or this context was created using CertCreateCertificateContext, the default PROV_RSA_FULL provider calculates the hash.

pvData points to the array of bytes and not a HASH_BLOB as used by pvData in CertSetCertificateContextProperty.

CERT_KEY_CONTEXT_PROP_ID
pvData points to a CERT_KEY_CONTEXT structure.
CERT_KEY_SPEC_PROP_ID
A DWORD containing the specification of the private key (dwKeySpec) is returned in pvData. If the CERT_KEY_CONTEXT_PROP_ID exists, dwKeySpec is obtained from there. Otherwise, if the CERT_KEY_PROV_INFO_PROP_ID exists, it is the source of the dwKeySpec.
CERT_ENHKEY_USAGE_PROP_ID or CERT_CTL_USAGE_PROP_ID
An array of bytes containing an ASN.1 encoded CTL_USAGE data structure is returned in the location pointed to by pvdata. *pcbData returns with the length of the CTL_USAGE structure.
CERT_NEXT_UPDATE_LOCATION_PROP_ID
An array of bytes containing an ASN.1 encoded CERT_ALT_NAME_INFO data structure is returned in the location pointed to by pvData. *pcbData returns the length of the data structure. CERT_NEXT_UPDATE_LOCATION_PROP_ID if currently used only with CTLs.
CERT_FRIENDLY_NAME_PROP_ID
A NULL terminated unicode character string specifying the friendly name for a certificate, CRL, or CTL is returned in the location pointed to by pvdata. *pcbData returns the length of the string.
CERT_PVK_FILE_PROP_ID
A NULL terminated unicode, wide character string specifying the file name containing the private key associated with the certificate's public key is returned in the location pointed to by pvData. *pcbData returns the length of the string.
CERT_SIGNATURE_HASH_PROP_ID
If the hash does not exist, it is computed with CryptHashToBeSigned. The existing or computed hash of the signature is returned in the location pointed to by pvData. The length of the hash is 20 bytes for SHA and 16 for MD5.
CERT_ACCESS_STATE_PROP_ID
A DWORD that indicates whether writes to the certificate are persisted. It is not set if the certificate is in a memory store or in a registry based store that is opened as read only.
All other PROP_IDs
pvData points to the array of bytes and not a CRYPT_DATA_BLOB as used by pvData in CertSetCertificateContextProperty.

See the documentation on dwPropId in CertSetCertificateContextProperty for more details about each property ID.

pvData
Pointer to a buffer that receives the data as determined by dwPropId. Elements pointed to by fields in the pvData structure follow the structure. Therefore, the size contained in pcbData may exceed the size of the structure.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pvData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes to be stored in the buffer. This parameter can be NULL, only if pvData is NULL.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError may be called to indicate the reason for any failure. This function uses the following error code:

ERROR_MORE_DATA
If the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
CRYPT_E_NOT_FOUND
The certificate does not have the specified property.

Errors from the called function CryptHashCertificate may be propagated to this function.

Example

See CertEnumCertificateContextProperties.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertSetCertificateContextProperty


CertGetCRLContextProperty

The CertGetCRLContextProperty function gets a property for the specified CRL context.

#include <wincrypt.h>
BOOL WINAPI CertGetCRLContextProperty(
  PCCRL_CONTEXT pCrlContext,     // in
  DWORD dwPropId,                // in
  void *pvData,                  // out
  DWORD *pcbData                 // in/out
);

Parameters

pCrlContext
Pointer to the CRL context.
dwPropId
ID for the desired property.

See CertGetCertificateContextProperty for a complete list of property IDs.

pvData
Pointer to a buffer that receives the data as indicated by dwPropId. Elements pointed to by fields in the pvData structure follow the structure. Therefore, the size contained in pcbData may exceed the size of the structure.

This parameter can be NULL if to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pvData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pvData is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called function CryptHashCertificate may be propagated to this function. This function has the following error codes:

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
CRYPT_E_NOT_FOUND | The CRL doesn't have the specified property.

Example

See the example for CertEnumCertificateContextProperties, and extrapolate from a certificate to a CRL ( PCCERT_CONTEXT becomes PCCRL_CONTEXT, pCertContext becomes pCrlContext, CertEnumCertificateContextProperties becomes CertEnumCRLContextProperties, and CertGetCertificateContextProperty becomes CertGetCRLContextProperty).

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertEnumCRLContextProperties


CertGetCRLFromStore

The CertGetCRLFromStore function gets the first or next CRL_CONTEXT from the certificate store for the specified issuer certificate and performs. Performs the enabled verification checks on the CRL.

#include <wincrypt.h>
PCCRL_CONTEXT WINAPI CertGetCRLFromStore(
  HCERTSTORE hCertStore,                // in
  PCCERT_CONTEXT pIssuerContext,        // in, optional
  PCCRL_CONTEXT pPrevCrlContext,        // in
  DWORD *pdwFlags                       // in/out
);

Parameters

hCertStore
Handle to the certificate store.
pIssuerContext
Optional, it is a pointer to an issuer certificate context. The pIssuerContext may have been obtained from this store or another store, or created by the caller application. When created by the caller, the CertCreateCertificateContext function must have been called. If NULL is passed for this parameter, all the CRLs in the store will be found.
pPrevCrlContext
Pointer to a CRL_CONTEXT. An issuer may have multiple CRLs. For example, it can generate delta CRLs by using an X.509 v3 extension. This parameter must be NULL on the first call to get the CRL. To get the next CRL for the issuer, the parameter is set to the CRL_CONTEXT returned by a previous call. A non-NULL pPrevCrlContext is always freed by this function by using a call to CertFreeCRLContext, even for an error.
pdwFlags
The following flags can be set in *pdwFlags to enable verification checks on the returned CRL:
Flag name Description
CERT_STORE_SIGNATURE_
FLAG 		Use the public key in the issuer's certificate to verify the signature on the returned CRL.
CERT_STORE_TIME_
VALIDITY_FLAG 		Get the current time and verify that it's within the CRL's "ThisUpdate" and "NextUpdate" validity period.

If an enabled verification check succeeds, its flag is set to zero. If an enabled verification check fails, then its flag is set upon return. If pIssuerContext is NULL, then an enabled CERT_STORE_SIGNATURE_FLAG always fails and the CERT_STORE_NO_ISSUER_FLAG is also set. For more details see the Remarks section.

For a verification check failure, a pointer to the first or next CRL_CONTEXT is still returned and SetLastError isn't updated.

Return Values

If the first or next CRL is not found, NULL is returned. Otherwise, a pointer to a read-only CRL_CONTEXT is returned. The CRL_CONTEXT must be freed by calling CertFreeCRLContext. However, when the returned CRL_CONTEXT is supplied for pPrevCrlContext on a subsequent call, the function frees it.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | The hCertStore argument isn't the same as the hCertStore in the CRL context pointed to by the pPrevCrlContext argument. Unsupported bit was set in *pdwFlags.
CRYPT_E_NOT_FOUND | Either no CRLs in the store for the issuer or reached the end of the store's list.

Remarks

CertDuplicateCRLContext can be called to make a duplicate CRL.

The hexadecimal values of the flags may be combined together with a bitwise OR operation in order to enable both verifications. For example, to enable both verifications the value 0x00000003 would be placed in the double word *pdwFlags, and the pointer to this word is passed in pdwFlags. If CERT_STORE_SIGNATURE_FLAG verification succeeded, but CERT_STORE_TIME_VALIDITY_FLAG verification failed, *pdwFlags would be set to 0x00000002 when the function returns.

Example

See the example for CertEnumCertificatesInStore, change all references from "certificate" to "CRL."

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetCRLContextProperty


CertGetCTLContextProperty

The CertGetCTLContextProperty function gets a property for the specified CTL context.

#include <wincrypt.h>
BOOL WINAPI CertGetCTLContextProperty(
  PCCTL_CONTEXT pCtlContext,   // in
  DWORD dwPropId,              // in
  void *pvData,                // out
  DWORD *pcbData               // in/out
);

Parameters

pCtlContext
Pointer to the CTL context.
dwPropId
ID for the desired property.

See CertGetCertificateContextProperty for a complete list of property IDs. CERT_SHA1_HASH_PROP_ID or CERT_NEXT_UPDATE_LOCATION_PROP_ID are the predefined properties of most interest.

pvData
Pointer to a buffer that receives the data as indicated by dwPropId. Elements pointed to by fields in the pvData structure follow the structure. Therefore, the size contained in pcbData may exceed the size of the structure.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pvData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pvData is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called function CryptHashCertificate may be propagated to this function. This function has the following error codes:

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pvData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbData.
CRYPT_E_NOT_FOUND | The CTL doesn't have the specified property.

Example

See the example for CertEnumCertificateContextProperties, and extrapolate from a certificate to a CTL ( PCCERT_CONTEXT becomes PCCTL_CONTEXT, pCertContext becomes pCTLContext, CertEnumCertificateContextProperties becomes CertEnumCTLContextProperties, and CertGetCertificateContextProperty becomes CertGetCTLContextProperty).

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertEnumCTLContextProperties, CertSetCTLContextProperty


CertGetIssuerCertificateFromStore

The CertGetIssuerCertificateFromStore function gets the certificate context from the certificate store for the first or next issuer of the specified subject certificate. The function also performs enabled verification checks on the subject certificate using the returned issuer certificate.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(
  HCERTSTORE hCertStore,                  // in
  PCCERT_CONTEXT pSubjectContext,         // in
  PCCERT_CONTEXT pPrevIssuerContext,      // in, optional
  DWORD *pdwFlags                         // in/out
);

Parameters

hCertStore
Handle to the certificate store.
pSubjectContext
Pointer to a subject context. This parameter may be obtained from any certificate store or be created by the caller application using the CertCreateCertificateContext function.
pPrevIssuerContext
Pointer to an issuer context. An issuer may have multiple certificates especially when a validity period is about to change. This parameter must be NULL on the first call to get the first issuer certificate. To get the next certificate for the issuer, set pPrevIssuerContext to the CERT_CONTEXT returned by the previous call.

A pPrevIssuerContext that is not NULL is always freed by this function by using CertFreeCertificateContext, even for an error.

pdwFlags
The following flags can be set in dwFlags to enable verification checks on the returned certificate:
Flag name | Description
CERT_STORE_NO_CRL_FLAG | Value returned if no matching CRL was found.
CERT_STORE_NO_ISSUER_FLAG | Value returned if no issuer certificate was found.
CERT_STORE_REVOCATION_FLAG | Check whether the subject certificate is on the issuer's revocation list.
CERT_STORE_SIGNATURE_FLAG | Use the public key in the issuer's certificate to verify the signature on the subject certificate.
CERT_STORE_TIME_VALIDITY_FLAG | Get the current time and verify that it is within the subject certificate's validity period.

If an enabled verification check succeeds, its flag is set to zero. If it fails, its flag remains set upon return. For CERT_STORE_REVOCATION_FLAG, the verificantion succeeds if it does not find a CRL related to the subject certificate.

If CERT_STORE_REVOCATION_FLAG was enabled and the issuer does not have a CRL in the store, CERT_STORE_NO_CRL_FLAG is set in addition to setting CERT_STORE_REVOCATION_FLAG to zero.

If CERT_STORE_SIGNATURE_FLAG or CERT_STORE_REVOCATION_FLAG is set, CERT_STORE_NO_ISSUER_FLAG is set if it does not have an issuer certificate in the store. For more details see the Remarks section.

For a verification check failure, a pointer to the issuer's CERT_CONTEXT is still returned and SetLastError is not updated.

Return Values

If the first or next issuer certificate is not found, NULL is returned. Otherwise, a pointer to a read-only issuer CERT_CONTEXT is returned. The CERT_CONTEXT must be freed by calling CertFreeCertificateContext; however, when the returned CERT_CONTEXT is supplied for pPrevIssuerContext on a subsequent call, the function frees it.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
CRYPT_E_NOT_FOUND | No issuer was found for the subject certificate.
CRYPT_E_SELF_SIGNED | The issuer certificate is the same as the subject certificate. It is a self-signed root certificate.
E_INVALIDARG | The hCertStore argument is not the same as the hCertStore in the certificate context pointed to by the pPrevCertContext argument or an unsupported bit was set in *pdwFlags.

Remarks

CertDuplicateCertificateContext can be called to make a duplicate of the issuer certificate.

The hexadecimal values of the dwFlags may be combined using a bitwise OR operation to enable multiple verifications. For example, to enable both signature and time validity, the value 0x00000003 would be placed in the double word dwFlags as the "in" parameter. If CERT_STORE_SIGNATURE_FLAG verification succeeded, but CERT_STORE_TIME_VALIDITY_FLAG verification failed, dwFlags would return set to 0x00000002, as an "out" parameter.

Example

//
// Find the first or next certificate for the issuer
// of a subject certificate using
// CertGetIssuerCertificateFromStore
//
#define MY_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
//
// The handle_error function is defined in a separate file.
//
HCERTSTORE     hFileStore;     // Handle for the cert store where the
                               // subject certificate will be found.
HCERTSTORE     hCertStore;     // The store in which to find
                               // the issuer certificate.
PCCERT_CONTEXT pSubjectContext;// The certificate with an issuer
// to be matched.
PCCERT_CONTEXT pIssuerContext; // NULL for the first call.
// For subsequent calls,
// a pointer to the context
// returned by the previous call.
DWORD dwFlags;                 // Flags to specific conditions
                               // to be verified. A pointer to this
                               // DWORD is passed to the function as
                               // an in/out parameter.

// Open a file based certificate store to find a subject certificate.
// For details, see CertOpenStore.
if(hFileStore=CertOpenStore(
CERT_STORE_PROV_FILENAME,
MY_TYPE,
NULL,
0,
L"teststor.sto"))
printf("The file based store is open. Continue.\n");
else
handle_error("The file store did not open.");
// Get the first certificate from the file store.
if(pSubjectContext=CertEnumCertificateInStore(hFileStore,NULL))
printf("A certificate from the store is retrieved. Continue.\n"):
else
handle_error("No certificate retrieved. The store may be empty.");
// Open a second certificate store to find a subject certificate.
// For details, see CertOpenStore.
if(hCertStore=CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The second store is open. Continue. \n");
else
handle_error("The second store was not opened.");
// Set verification dwFlags
dwFlags = CERT_STORE_REVOCATION_FLAG;

// Call the CertGetIssuerCerticateFromStore function.
if(CertGetIssuerCertificateFromStore(
hCertStore,
pSubjectContext,
NULL,
&dwFlags))
printf("Issuer certificate found.\n");
else
handle_error("An issuer certificate was not found.");
// Check the verification results.
if( dwFlags > 0 )
{
printf("The flag was not re-set.\n");
printf("A CRL was found. This certificate has been revoked.\n");
}
else
{
printf("The flag was re-set.\n");
printf("The verification was successful.\n");
printf("No matching CRL was found. The certificate seems valid.\n");
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertGetStoreProperty

[This is preliminary documentation and subject to change.]

The CertGetStoreProperty function gets a store property.

#include <wincrypt.h>
BOOL CertGetStoreProperty(
  HCERTSTORE hCertStore,           // in
  DWORD dwPropId,                  // in
  void *pvData,                    // out
  DWORD *pcbData                   // in, out
);

Parameters

hCertStore
Handle for a certificate store.
dwPropId
DWORD indicating one of a range of user defined store properties. These values should be outside the current range of values for predefined context properties. Currently, user defined pwPropId values should begin at 4096.

There is one predefined store property, CERT_STORE_LOCALIZED_NAME_PROP_ID, the localized name of the store.

pvData
Pointer to a buffer that receives the data as determined by dwPropId. For CERT_STORE_LOCALIZED_NAME_PROP_ID, the localized name of the store, pvData points to a NULL terminated unicode, wide character string. For other dwPropIds, pvData points to an array of bytes.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions .

pcbData
Pointer to a DWORD that specifies the size, in bytes, of the buffer pointed to by the pvData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pvData is NULL.

Return Values

If the store property is found the function returns TRUE. pvDate points to the property and pcbData points to the length of the string. If the store property is not found, the function returns FALSE and GetLastError returns CRYPT_E_NOT_FOUND.

Remarks

Store property IDs are properties applicable to an entire store. They are not properties on an individual certificate, CRL, or CTL context. Currently, no store properties are persisted.

Example

//
// Example code for CertSetStoreProperty and CertGetStoreProperty
//
//
// handle_error is a function defined in a separate file.
//
HCERTSTORE hCertStore;
void *pvData=NULL;
DWORD cbData;
CRYPT_DATA_BLOB Property_Name_Blob;

// Open the MY certificate store.
// See CertOpenStore for details.
if ( hCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
L"MY"))
printf("The MY store is open. Continue. \n");
else
handle_error("The MY store did not open.");
// Prepare a data strucute to set a store property.
// Initialize the members of the CRYPT_DATA_BLOB.
Property_Name_Blob.pbData =(BYTE *) L"The name of MY Store";
Property_Name_Blob.cbData = (wcslen((LPWSTR) Property_Name_Blob.pbData)+1) * sizeof(WCHAR);
// Set the store's localized name property.
if (CertSetStoreProperty(
hCertStore,
CERT_STORE_LOCALIZED_NAME_PROP_ID,
0,
&Property_Name_Blob)
printf("The name of the store has been set. Continue. \n");
else
handle_error("Setting the store's localized name failed.");
// Call CerGetStorePropertyt a first time
// to get the length of the store name string to be returned
if(CertGetStoreProperty(
hCertStore,
CERT_STORE_LOCALIZED_NAME_PROP_ID,
    NULL,     // NULL on the first call
              // to establish the length of the string to
              // to be returned.
&cbData)))
printf("The first call succeed. Continue.\n");
else
handle_error("The first call to the function failed.");
// cbData is the length of a string to be allocated.
// Allocate the space for the string and call the function a
//  the second time.
if(pvData = malloc(cbData)
printf("Memory is allocated. Continue. \n");
else
handle_error("Memory was not allocated.");
if(CertGetStoreProperty(
hCertStore,
CERT_STORE_LOCALIZED_NAME_PROP_ID,
pvData,
&cbData))
printf("The second call to the function worked. Continue.\n");
else
handle_error("The second call to CertGetStoreProperty failed.");
// Print the name of the store.
printf("The localized name is %S.\n",pvData);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertSetStoreProperty


CertGetSubjectCertificateFromStore

The CertGetSubjectCertificateFromStore function gets the subject certificate context that is uniquely identified by its issuer and serial number from the certificate store.

#include <wincrypt.h>
PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(
  HCERTSTORE hCertStore,        // in
  DWORD dwCertEncodingType,     // in
  PCERT_INFO pCertId            // in
);

Parameters

hCertStore
Handle to the certificate store.
dwCertEncodingType
Type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pCertId
Pointer to a CERT_INFO structure. Only the Issuer and SerialNumber fields are used.

Return Values

A pointer to a read-only CERT_CONTEXT is returned. The CERT_CONTEXT must be freed by calling CertFreeCertificateContext.

The returned certificate might not be valid. Normally, it would be verified when getting its issuer certificate (CertGetIssuerCertificateFromStore).

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
CRYPT_E_NOT_FOUND | Unable to find the subject certificate in the store.

Remarks

CertDuplicateCertificateContext can be called to make a duplicate certificate.

Example

See Signed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetIssuerCertificateFromStore


CertOpenStore

[This is preliminary documentation and subject to change.]

The CertOpenStore function opens a certificate store using a specified store provider type. This function provides simple ways to open a certificate store for ordinary purposes and more complex options for special cases.

#include <wincrypt.h>
HCERTSTORE WINAPI CertOpenStore(
  LPCSTRlpszStoreProvider,                // in
  DWORD dwMsgAndCertEncodingType,         // in
  HCRYPTPROV hCryptProv,                  // in
  DWORD dwFlags,                          // in
  const void *pvPara                      // in
);

Parameters

lpszStoreProvider
Specifies the store provider type. The following predefined store provider types furnish most common application needs.
CERT_STORE_PROV_MEMORY
CERT_STORE_PROV_FILE
CERT_STORE_PROV_FILENAME
CERT_STORE_PROV_COLLECTION
CERT_STORE_PROV_REG
CERT_STORE_PROV_SYSTEM
CERT_STORE_PROV_SYSTEM_REGISTRY
CERT_STORE_PROV_PHYSICAL
CERT_STORE_PROV_MSG
CERT_STORE_PROV_PKCS7
CERT_STORE_PROV_SERIALIZED
CERT_STORE_PROV_LDAP

Most of the provider names passed to lpszStoreProvider may be prefixed with 'sz_' as in sz_CERT_STORE_PROV_FILE. Calling a provider with a name prefixed by 'sz_' does not change that provider in any way.

Provider types that pass a string to pvPara have alternate forms: one that passes the string as unicode ( an LPCWSTR variable) and another that passes the string as ASCII ( an LPCSTR variable). The names of providers that pass ASCII strings must be suffixed with '_A' as in CERT_STORE_PROV_FILENAME_A. Providers that pass unicode strings may be suffixed with '_W' as in sz_CERT_STORE_PROV_REG_W. Provider names without either the '_A' or '_W' use the default, unicode form.

The store provider type passed in lpszStoreProvider determines the type of the parameter passed in pvPara and the use and meaning of the HIWORD of dwFlags.

The predefined store provider types are defined as follows:

CERT_STORE_PROV_MEMORY
Creates a certificate store in cached memory but no certificates, CRLs, or CTLs are initially loaded into the store This provider type is typically used to create a temporary store.

pvPara is not used.

Any addition of certificates, CRLs, or CTLs or changes in properties of certificates, CRLs, or CTLs in a memory store are not automatically saved. They may be saved to a file or to a memory blob using CertSaveStore.

CERT_STORE_PROV_FILE.
Initializes the store with certificates, CRLs, and CTLs read from a specified open file.

This provider expects the file to contain only a serialized store and not either PKCS #7 signed messages or a single encoded certificate.

The handle of a file opened using CreateFile is passed in pvPara. The file pointer should be positioned at the beginning of the serialized store information. After the data in the serialized store has been loaded into the certificate store, the file pointer is positioned at the beginning of any data that may follow the serialized store data in the file.

If dwFlags CERT_FILE_STORE_COMMIT_ENABLE is set, the file handle is duplicated and the store is always committed as a serialized store.

The file is not closed when the store is closed.

CERT_STORE_PROV_FILENAME
Initializes the store with certificates, CRLs, and CTLs from a file. The provider opens the file and first attempts to read the file as a serialized store, then as a PKCS #7 signed message, and, finally, as a single encoded certificate.

dwMsgAndCertEncodingType must contain the encoding types to be used with both messages and certificates.

For the FILENAME providers: if the file contains an X509 encoded certificate, the open fails with ERROR_ACCESS_DENIED.

If dwFlags CERT_STORE_CREATE_NEW_FLAG and CERT_FILE_STORE_COMMIT_ENABLE are set, CreateFile uses CREATE_NEW. If CERT_STORE_OPEN_EXISTING is set, it uses OPEN_EXISTING. Otherwise, it defaults to OPEN_ALWAYS.

If CERT_FILE_STORE_COMMIT_ENABLE is set, the file is committed as either a PKCS #7 or a serialized store depending on the type read when the file opened. However, if the file was empty, if the filename has either a ".p7c" or ".spc" extension it is committed as a PKCS #7. Otherwise, its committed as a serialized store.

The name of an existing, unopened file is passed in pvPara as a unicode or ASCII string.

CERT_STORE_PROV_COLLECTION
Opens a store that will be a collection of other stores. Stores are added to or removed from the collection using CertAddStoreToCollection and CertRemoveStoreFromCollection. When a store is added to a collection, all certificates, CRLs, and CTLs in that store become available to finds or enumerations of the collection store.

pvPara should be set to NULL and the HIWORD of dwFlags set to 0.

CERT_STORE_PROV_REG.
Initializes the store with certificates, CRLs, and CTLs from a registry. subkey. The handle of an open registry hKey is passed in pvPara.

This provider opens or creates "Certificates," "CRLs," and "CTLs" registry subkeys under the hKey passed in pvPara. The input hKey is not closed by the provider. Before returning, the provider opens its own copy of the hKey passed in pvPara.

When CERT_STORE_READONLY_FLAG is set in the LOWORD of dwFlags, registry subkeys are opened via RegOpenKey with KEY_READ_ACCESS. Otherwise, registry subkeys are created via RegCreateKey with KEY_ALL_ACCESS.

Any changes to the contents of the opened store are immediately persisted to the registry. However, if CERT_STORE_READONLY_FLAG is set in the LOWORD of dwFlags , any attempt to add to the contents of the store or to change a context's property results in an error with GetLastError returning E_ACCESSDENIED.

CERT_STORE_PROV_SYSTEM
Initializes the store with certificates, CRLs, and CTLs from the specified system store. The system store is a logical, collection store consisting of one or more physical stores. A physical store associated with a system store is registered with the CertRegisterPhysicalStore function. After the system store is opened, all of the physical stores that are associated with it are also opened by calls to CertOpenStore and are added to the system store collection using CertAddStoreToCollection.

The HIWORD of dwFlags indicates the system store location, normally set to CERT_SYSTEM_STORE_CURRENT_USER. See the section on dwFlags and System Store Locations for details about registry locations.

Some system store locations can be open remotely. See System Store Locations for details.

A system store name, passed as a unicode or ASCII string, such as "MY," or "Root," is passed in pvPara.

CERT_STORE_PROV_SYSTEM_REGISTRY
Initializes the store with certificates, CRLs, and CTLs from a physical registry store. The physical store is not opened as a collection store. Enumerations and finds go through only the certificates, CRLs, and CTLs in that one physical store. The implementation of this provider is the same as the CERT_STORE_PROV_SYSTEM provider implemented in NT 4.0.

The HIWORD of dwFlags indicates the system store location, normally set to CERT_SYSTEM_STORE_CURRENT_USER. See the section on dwFlags.

Some system store locations can be open remotely. See System Store Locations for details.

A system store name, passed as a unicode or ASCII string, such as "MY," or "Root," is passed in pvPara.

CERT_STORE_PROV_PHYSICAL
Initializes the store with certificates, CRLs and CTLs from a specified physical store that is a member of a logical system store.

The HIWORD of dwFlags indicates the system store location, normally CERT_SYSTEM_STORE_CURRENT_USER. See the section on dwFlags for details.

Some physical store locations can be open remotely. Both the system store name and physical names are passed in pvPara. The two names are separated with an intervening "\", as, for example, "Root\.LocalMachine." Here, Root is the name of the system store and .LocalMachine is the name of the physical store. The system and physical store names are unicode strings and can not contain any backslashes.

CERT_STORE_PROV_MSG.
Initializes the store with certificates, CRLs, and CTLs from the specified cryptographic message. dwMsgAndCertEncodingType must contain the encoding types used with both messages and certificates. The HCRYPTMSG handle of the encoded message, returned by a call to CryptMsgOpenToDecode , is passed in pvPara
CERT_STORE_PROV_PKCS7
Initializes the store with certificates, CRLs, and CTLs from an encoded PKCS #7 signed message. dwMsgAndCertEncodingType must specify the encoding types to be used with both messages and certificates. A pointer to the encoded message's blob, a CRYPT_DATA_BLOB, is passed in pvPara
CERT_STORE_PROV_SERIALIZED
Initializes the store with certificates, CRLs, and CTLs from a memory location containing a serialized store.

A pointer to a CRYPT_DATA_BLOB serialized memory blob is passed in pvPara.

CERT_STORE_PROV_LDAP
Initializes the store with certificates, CRLs, and CTLs from the results of the query specified by a LDAP URL. The query as a unicode string is passed in pvPara. In order to do writes to the store, the URL must specify a BASE query with no filter and a single attribute.

Additional store providers may be installed or registered via CryptInstallOIDFunctionAddress or CryptRegisterOIDFunction. For additional information, see Extending CertOpenStore Functionality.

dwMsgAndCertEncodingType
This parameter is applicable only to the CERT_STORE_PROV_MSG, CERT_STORE_PROV_PKCS7, or CERT_STORE_PROV_FILENAME provider types. For all other provider types, this parameter is unused and should be set to 0. The LOWORD specifies the encoding type of certificates, CRLs, and CTLs in the cryptographic message. The HIWORD specifies the encoding type of the message.

Both a certificate and a message encoding type are required. They are specified by combining the two encoding types with a bitwise OR operation. The most common encoding types are used by passing X509_ASN_ENCODING | PKCS_7_ASN_ENCODING as this parameter.

hCryptProv
Specifies a handle to a cryptographic provider. Passing NULL in this parameter causes an appropriate, default provider to be used. Using the default provider is recommend. The default or specified cryptographic provider verifies the signature of a subject certificate, CRL, or CTL and to compute the hash when CertGetCertificateContextProperty , CertGetCTLContextProperty, or CertGetCRLContextProperty is called with hash PROP_IDs
dwFlags
dwFlags consist of HIWORD and LOWORD values that are combined using a bitwise OR.

The LOWORD portion of dwFlags control a variety of general characteristics of the certificate store opened. It can be used with all store provider types. Currently defined LOWORD portions values are:
CERT_STORE_NO_CRYPT_RELEASE_FLAG
CERT_STORE_READONLY_FLAG
CERT_STORE_DELETE_FLAG
CERT_STORE_OPEN_EXISTING_FLAG
CERT_STORE_CREATE_NEW_FLAG
CERT_STORE_SET_LOCALIZED_NAME_FLAG
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG

CERT_STORE_NO_CRYPT_RELEASE_FLAG
This flag is valid only when a non-default cryptographic provider is used. When this flag is set, a non-default hCryptProv is not automatically released when the certificate store is closed.
CERT_STORE_READONLY_FLAG
When this flag is set, any attempt to change the contents of the store results in an error. When this flag is set and a registry based store provider is being used, the registry subkeys are opened via RegOpenKey with KEY_READ_ACCESS. Otherwise, the registry subkeys are created via RegCreateKey with KEY_ALL_ACCESS.
CERT_STORE_DELETE_FLAG.
When this flag is set, the store is deleted instead of being opened. CertOpenStore returns NULL for both success and failure of the deletion. To determine the success of the delete, call GetLastError which returns 0 if the store was deleted and nonzero if it was not deleted.
CERT_STORE_OPEN_EXISTING_FLAG.
When set, only an existing store can be opened. If the store did not exist, the function fails.
CERT_STORE_CREATE_NEW_FLAG.
When set, a new store is created if one did not exist. The function fails if the store already exists.

If neither CERT_STORE_OPEN_EXISTING_FLAG nor CERT_STORE_CREATE_NEW_FLAG is set, a store is opened if it exists, or is created and opened if it did not already exist.

CERT_STORE_SET_LOCALIZED_NAME_FLAG
If supported, the provider sets the store's CERT_STORE_LOCALIZED_NAME_PROP_ID property. This name can be retrieved by calling CertGetStoreProperty with dwPropID set to CERT_STORE_LOCALIZED_NAME_PROP_ID. This flag is supported for providers CERT_STORE_PROV_FILENAME, CERT_STORE_PROV_SYSTEM, CERT_STORE_PROV_SYSTEM_REGISTRY, and CERT_STORE_PROV_PHYSICAL_W.
CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG
When this flag is set, the closing of a store's provider may not be done when CertCloseStore is called but will deferred if certificates, CRLs, or CTLs obtained from the store are still in use. The store will actually be closed when the last certificate, CRL, or CTL obtained from the store is freed. Any changes made to properties of these certificates, CRLs, and CTLs, even after the call to CertCloseStore, will be persisted.

If this flag is not set and certificates, CRLs, or CTL obtained from the store are still in use, the properties of those certificates, CRLs and CTLs may be changed, but those changes will not be persisted. By setting this flag, those changes will be persisted.

Note that setting this flag causes extra overhead in doing context duplications and frees.

If CertCloseStore is called with CERT_CLOSE_STORE_FORCE_FLAG, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG is ignored,

When this flag is set and a non-NULL HCRYPTPROV is passed, that provider will continue to be used even after the call to CertCloseStore.

dwFlags HIWORD values are combined using a bitwise OR with LOWORD flag values

The HIWORD of dwFlags is used to specify system store registry locations for system store provider types, CERT_STORE_PROV_SYSTEM, CERT_STORE_PROV_SYSTEM_REGISTER, and CERT_STORE_PROV_PHYSICAL. The following are defined HIWORD values associated with system store providers:

CERT_SYSTEM_STORE_CURRENT_USER
CERT_SYSTEM_STORE_LOCAL_MACHINE
CERT_SYSTEM_STORE_CURRENT_SERVICE
CERT_SYSTEM_STORE_SERVICES
CERT_SYSTEM_STORE_USERS
CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

Each system store location opens, by default, relative to the HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE or HKEY_USERS predefined registry key. See System Store Locations for additional details.

Two additional system store flags can set in the HIWORD of dwFlags:

CERT_SYSTEM_STORE_RELOCATE_FLAG
CERT_SYSTEM_STORE_UNPROTECTED_FLAG

CERT_SYSTEM_STORE_RELOCATE_FLAG
This flag can be set to override the default location of a system store. When it is set, pvPara must pass a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA structure rather than a string. The data structure indicates both the name of the store and its location in the registry.
CERT_SYSTEM_STORE_UNPROTECTED_FLAG
By default, when the CurrentUser "Root" store is opened, any SystemRegistry roots not on the protected root list are deleted from the cache before CertOpenStore returns. When this flag is set, this default is overridden and all of the roots in the SystemRegistry are returned and no check of the protected root list is made.

Two addition HIWORD flags have been added for the CERT_STORE_PROV_REGISTRY provider.

CERT_REGISTRY_STORE_SERIALIZED_FLAG
CERT_REGISTRY_STORE_REMOTE_FLAG

CERT_REGISTRY_STORE_SERIALIZED_FLAG
When this flag is set, the CERT_STORE_PROV_REG provider saves certificates, CRLs, and CTLs into a single, serialized store subkey instead of the default which is that each certificate, CRL, or CTL is saved as a separate registry subkey under the appropriate subkey.

This flag is mainly used for stores downloaded from the GPT such as the CurrentUserGroupPolicy and LocalMachineGroupPolicy stores.

When CERT_REGISTRY_STORE_SERIALIZED_FLAG is set, store adds, deletes, or property changes are not persisted until there is a call to either CertCloseStore or CertControlStoreusing CERT_STORE_CTRL_COMMIT.

CERT_REGISTRY_STORE_REMOTE_FLAG
When this flag is set, the hKey passed in pvPara points to a registry key on a remote computer. To access a registry key on a remote computer, Security Permissions on the remote computer must be set to allow access. See the Remarks section for further details.

One HIWORD flag, CERT_FILE_STORE_COMMIT_ENABLE, has been added for the file provider types, CERT_STORE_PROV_FILE, and CERT_STORE_PROV_FILENAME.

When this flag is set, any additions to the store or any changes made to properties of contexts in the store are committed to the file store either when CertCloseStore is called or when CertControlStore is called with CERT_STORE_CONTROL_COMMIT.

CertOpenStore fails with E_INVALIDARG if both CERT_FILE_STORE_COMMIT_ENABLE and CERT_STORE_READONLY_FLAG are set in dwFlags.

pvPara
Pointer to a VOID that can point to data of different data types depending on which provider is being used. Detailed information about the type and content to be passed in pvPara is given in the descriptions of the available providers.

Return Values

If CertOpenStore fails, NULL is returned. Otherwise, a handle to the certificate store is returned.

GetLastError returns an error code if the function fails; however, CreateFile, ReadFile, or registry errors may be propagated and their error codes will be returned. CertOpenStore has a single error code of its own; ERROR_FILE_NOT_FOUND which indicates that the function was unable to find the provider specified by lpszStoreProvider parameter.

Remarks

A system store is a collection consisting of one or more physical sibling stores. For each system store, there are predefined physical sibling stores. After opening a system store such as MY at CERT_SYSTEM_STORE_CURRENT_USER, CertOpenStore is called to open of all of the physical stores in the system store collection. Each of these physical stores is added to the system store collection using CertAddStoreToCollection. All certificates, CRLs, and CTLs in those physical stores are available through the logical system store collection.

The following system store locations can be opened remotely:

CERT_SYSTEM_STORE_LOCAL_MACHINE

CERT_SYSTEM_STORE_SERVICES

CERT_SYSTEM_STORE_USERS

CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

System store locations are opened remotely by prefixing the store name in the string passed to pvPara with the computer name. Examples of remote system store names are:

ComputerName\CA

\\ComputerName\CA

ComputerName\ServiceName\Trust

\\ComputerName\ServiceName\Trust

For additional information on system stores, see System Store Locations.

To access a remote store, the Security Permissions in the registry keys on the remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

//==================================================
// This code provides examples of opening the most
// common certificate stores.
// For additional examples, see Example Code for
// Opening a Certificate Store.
//==================================================

// 1. Open the MY system store.
HCERTSTORE hSys_Store;
hSys_Store = CertOpenStore(
   CERT_STORE_PROV_SYSTEM,   // The store provider type.
   0,                        // The encoding type is not needed.
   NULL,                     // Use the default HCRYPTPROV.
CERT_SYSTEM_STORE_CURRENT_USER,
// Set store location in a registry
// location.
L"MY"                     // The store name as a unicode string.
   );
// Substitute in other common system store names for "MY"
// including "root", "trust", or "CA".
// Open a memory store.
HCERTSTORE hMem_Store;
hMem_Store = CertOpenStore(
   CERT_STORE_PROV_MEMORY,   // The memory provider type.
   0,                        // The encoding type is not needed.
   NULL,                     // Use the default HCRYPTPROV.
   0,                        // Accept the default dwFlags.
   NULL                      // pvPara not used.
   );

// Open a store from disk. In this example, the read only flag is set.
HANDLE       hFile;
HCERTSTORE   hFile_Store;
LPCSTR       pszFileName = "TestStor2.sto"
//  First, obtain a file handle.
if( !(hFile = CreateFile(
    pszFileName,                  // The file name
    GENERIC_READ|GENERIC_WRITE,   // Access mode:
                                  // read from and write to this file
    0,                            // Share Mode
    NULL,                         // Security
    OPEN_ALWAYS,                  // How to create
    FILE_ATTRIBUTE_NORMAL,        // File Attributes
    NULL)))                       // Template
{
printf("Could not open %s On Disk\n", pszFileName);
goto error_routine;
}
//   At this point, and data in the open file that precedes the
//   serialized cert store data may be used. The file pointer must
//   be placed at the beginning of the cert store data before
//   CertOpenStore with the CERT_STORE_PROV_FILE provider is called.
//   Open the store
if ( ! (hFile_Store = CertOpenStore(
    CERT_STORE_PROV_FILE,     //  Load certificates from a file.
    0,                        //  Encoding type not used.
    NULL,                     //  Use the default HCRYPTPROV.
CERT_STORE_READONLY_FLAG  //  See the LOWORD of dwFlags to make
//  the store read only.
    hFile                     //  The handle for the open file
                              //  that is the source of the
                              //  certificates.
    )))
{
printf("Could not open the file store. \n");
goto error_routine;
}
// Include code to work with the certificates
// The data file from which the certificate store information has been
// read is still open. Any data in that file that follows the
// serialized store can be read from the file and used at this point.
// Close the file store and the file.
CertCloseStore(
hFile_Store,
CERT_CLOSE_STORE_CHECK_FLAG);
CloseHandle(hFile);
error_routine:
//  Here include any code to be done if the disk file
//  could not be opened

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

Example Code for Opening a Certificate Store, CertSaveStore, CertCloseStore.


CertOpenSystemStore

The CertOpenSystemStore function opens a system certificate store based on a subsystem protocol. Several subsystem protocols are predefined by the Microsoft® CryptoAPI, as described under the szSubsystemProtocol parameter.

#include <wincrypt.h>
HCERTSTORE WINAPI CertOpenSystemStore(
  HCRYPTPROV hProv,               // in
  LPCTSTR pszSubsystemProtocol    // in
);

Parameters

hProv
Specifies a handle to the cryptographic provider. This parameter specifies the cryptographic provider to use to verify the signature of a subject certificate, CRL, or CTL. It is also used to compute the hash when CertGetCertificateContextProperty or CertGetCRLContextProperty is called with hash property IDs. If hProv is NULL the default provider "1" is acquired for you. Otherwise, if hProv is not NULL, the indicated provider is used, but not automatically released. The same semantics as CertOpenStore apply when CERT_STORE_NO_CRYPT_RELEASE_FLAG is set.
pszSubsystemProtocol
String describing a subsystem protocol. Some examples of predefined subsystem protocols are:
Predefined subsystem protocol string | Description
"MY" | A Certificate store holding "My" certificates with their associated private keys.
"CA" | Certifying Authority certificates.
"ROOT" | Root certificates.
"SPC" | Software publisher certificates.

Return Values

If the store open fails, NULL is returned. Otherwise, a handle to the certificate store is returned.

Call GetLastError to see the reason for any failures. Note that errors from the called function CertOpenStore are propagated to this function.

Remarks

After the system store is opened, all the standard certificate store APIs can be used to manipulate the certificates. For example, CertAddEncodedCertificateToStore can be used to add certificates to the system store.

When done, the certificate store should be closed by using CertCloseStore.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT.

See Also

CertOpenStore, CertSaveStore, CertCloseStore


CertRegisterPhysicalStore

[This is preliminary documentation and subject to change.]

The CertRegisterPhysicalStore function adds a physical Store to a registry system store collection.

#include <wincrypt.h>
BOOL WINAPI CertRegisterPhysicalStore(
  const void *pvSystemStore,                // in
  DWORD dwFlags,                            // in
  LPCWSTR pwszStoreName,                    // in
  PCERT_PHYSICAL_STORE_INFO pStoreInfo,     // in
  void *pvReserved                          // in/optional
);

Parameters

pvSystemStore
Identifies the system store collect to which the physical store will be added. It points to either a NULL terminated unicode string or to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure. See CertRegisterSystemStore for details on using the data structure and on prepending a ServiceName or Computer name to the system store name string.
dwFlags
The HIWORD of the dwFlags parameter specifies the location of the system store. See CertRegisterSystemStore for details on defined HIWORD dwFlags and prepending ServiceName, UserNames, and ComputerNames to the system store name.

The following LOWORD dwFlags are also defined and may be ORed with HIWORD flags.

CERT_SYSTEM_STORE_RELOCATE_FLAG
When this flag is set, the system store is not in its default registry location and pvSystemStore must be a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure.
CERT_STORE_CREATE_NEW_FLAG
When this flag is set, the function fails if the physical store already exists in the store location.
pwszStoreName
Pointer to a unicode string that names the physical store to be added to the system store collection.
pStoreInfo
Pointer to a CERT_PHYSICAL_STORE_INFO data structure that provides basic information about the physical store.
pvReserved
This parameter is reserved for future use and must be set to NULL.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Remarks

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

LPCWSTR pwszSystemStore = L"My";
LPcWSTR pwszStoreName = L"newstore";
CERT_PHYSICAL_STORE_INFO PhysicalStoreInfo
DWORD dwFlags= CERT_SYSTEM_STORE_CURRENT_USER;

// Initalize the PhysicalStoreInfo data structure.
PhysicalStoreInfo.cbSize=sizeof(CERT_PHYSICAL_STORE_INFO);
PhysicalStoreInfo.pszOpenStoreProvider=CERT_STORE_PROV_FILENAME;
PhysicalStoreInfo.dwFlags=CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG;
PhysicalStoreInfo.dwPriority=1;
PhysicalStoreInfo.dwOpenEncodingType=PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
if(CertRegisterPhysicalStore(
     pwszSystemStoreName),
     dwFlags,
     pwszStoreName,
     &PhyStoreInfo,
     NULL
              ))
       {
printf("Physical store %S is registered \n",pwszStoreName);
printf("As a store under %S \n",pvSystemStore);
       }
else
printf("The physical store was not registered. \n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertUnregisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumSystemStore, CertEnumPhysicalStore


CertRegisterSystemStore

[This is preliminary documentation and subject to change.]

The CertRegisterSystemStore function registers a system store.

#include <wincrypt.h>
BOOL WINAPI CertRegisterSystemStore(
  const void *pvSystemStore,              // in
  DWORD dwFlags,                          // in
  PCERT_SYSTEM_STORE_INFO pStoreInfo,     // in
  void *pvReserved                        // in/optional
);

Parameters

pvSystemStore
Identifier of the system store to be registered. If CERT_SYSTEM_STORE_RELOCATE_FLAG is set in dwFlags, pvSystemStore points to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure; else it points to a NULL terminated unicode string that names the system store. With the appropriate settings of dwFlags, this may be a system store on a remote local machine. Stores on remote computers can be registered with the computer name as a prefix to the name of the system store. For example, a remote local machine store could be registered with pvSystemStore pointing to the string "\\ComputerName\Trust" or "ComputerName\Trust."

Leading "\\" backslashes are optional before a ComputerName.

dwFlags
The HIWORD of the dwFlags parameter is used to specify the location of the system store.

The following HIWORD dwFlags are defined:

CERT_SYSTEM_STORE_CURRENT_USER

CERT_SYSTEM_STORE_CURRENT_SERVICE

CERT_SYSTEM_STORE_SERVICES

CERT_SYSTEM_STORE_USERS

CERT_SYSTEM_STORE_LOCAL_MACHINE

CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

When CERT_SYSTEM_STORE_CURRENT_USER is set, pvSystemStore may be a system store name that is prefixed with the UserName.

When CERT_SYSTEM_STORE_CURRENT_SERVICE is set, pvSystemStore may be a system store name that is prefixed with the ServiceName.

When CERT_SYSTEM_STORE_SERVICES or CERT_SYSTEM_STORE_USERS is set pvSystemStore must be a system store name that is prefixed with the ServiceName or UserName.

Stores on remote computers can be registered for CERT_SYSTEM_STORE_LOCAL_MACHINE, CERT_SYSTEM_STORE_SERVICES, CERT_SYSTEM_STORE_USERS or CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

The following LOWORD dwFlags are also defined and may be ORed with HIWORD flags.

CERT_SYSTEM_STORE_RELOCATE_FLAG
When this flag is set the system store is not in its default register location and pvSystemStore must be a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure.
CERT_STORE_CREATE_NEW_FLAG
When this flag is set, the function fails if the system store already exists in the store location.
pStoreInfo
This parameter is reserved for future use and must be set to NULL.
pvReserved
This parameter is reserved for future use and must be set to NULL.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Remarks

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

DWORD dwFlags= CERT_SYSTEM_STORE_CURRENT_USER;
LPCWSTR pySystemName= L"NEWSTORE";  // for this setting of
                                    // dwFlags, the store name may
                                    // be prefixed with a user name.
if(CertRegisterSystemStore(
pvSystemName,
dwFlags,
NULL,
NULL
       ))
   printf("System store %S is registered \n",pvSystemName);
else
   printf("The system store did not register. \n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterPhysicalStore, CertUnregisterSystemStore, CertUnregisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumSystemStore, CertEnumPhysicalStore


CertRemoveStoreFromCollection

[This is preliminary documentation and subject to change.]

The CertRemoveStoreFromCollection function removes a sibling certificate store from a collection store.

#include <wincrypt.h>
void WINAPI CertRemoveStoreFromCollection(
  HCERTSTORE hCollectionStore,                 // in
  HCERTSTORE hSiblingStore,                    // in
);

Parameters

hCollectionStore
Handle to the collection certificate store.
hSiblingStore
Handle to the sibling certificate store to be removed from the collection store.

Return Values

Nothing is returned by this function.

Example

HCERTSTORE      hCollectionStore;
HCERTSTORE      hSiblingStore;
// See the example with CertAddStoreToCollection for code that
// opens a collection store and a store that is added to
// the collection store as a sibling store. Assume that code was
// used and that hSiblingStore is a member of the collection
// store hCollectionStore.
CertRemoveStoreFromCollection(
            hCollectionStore,    // Handle for the collection store.
            hSiblingStore        // Handle for the store to be
                                 // removed from the collection store
            );
// This function has no return value that can be checked.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddStoreToCollection, CertOpenStore


CertSaveStore

The CertSaveStore function saves the certificate store.

#include <wincrypt.h>
BOOL WINAPI CertSaveStore(
  HCERTSTORE hCertStore,           // in
  DWORD dwMsgAndCertEncodingType,  // in
  DWORD dwSaveAs,                  // in
  DWORD dwSaveTo,                  // in
  void *pvSaveToPara,              // in/out
  DWORD dwFlags                    // in
);

Parameters

hCertStore
Handle to the certificate store that is to be saved.
dwMsgAndCertEncodingType
The dwMsgAndCertEncodingType specifies the certificate and message encoding types when dwSaveAs is CERT_STORE_SAVE_AS_PKCS7. Otherwise, the dwMsgAndCertEncodingType parameter is not used.

Note Both a certificate and message encoding type are required and are specified by combining them with a bitwise OR operation, as shown in the following example:

X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwSaveAs
Specifies if the store can be saved as a serialized store (CERT_STORE_SAVE_AS_STORE) containing properties in addition to encoded certificates, CRL, and CTLs if the store can be saved as a PKCS #7 signed message (CERT_STORE_SAVE_AS_PKCS7) that does not include the properties.

Note, the CERT_KEY_CONTEXT_PROP_ID property (and its CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_SPEC_PROP_ID) is not saved into a serialized store.

The dwMsgAndCertEncodingType specifies the message encoding type when dwSaveAs is CERT_STORE_SAVE_AS_PKCS7.

dwSaveTo
The dwSaveTo and pvSaveToPara parameters specify where to save the store as follows:
For dwSaveTo equal to CERT_STORE_SAVE_TO_FILE:
Saves to the specified file. The file's handle is passed in pvSaveToPara. Given, HANDLE hFile; pvSaveToPara = (void *) hFile.
After a successful save, the file pointer is positioned after the last write.
For dwSaveTo equal to CERT_STORE_SAVE_TO_MEMORY:
Saves to the specified memory blob. The pointer to the memory blob is passed in pvSaveToPara. Given, CRYPT_DATA_BLOB SaveBlob; pvSaveToPara = (void *) &SaveBlob.

Upon entry, SaveBlob's pbData and cbData need to be initialized.

Upon return, cbData is updated with the actual length.

For a length only calculation, pbData should be set to NULL. If pbData is non-NULL and cbData is not large enough, FALSE is returned with a last error of ERROR_MORE_DATA.

For dwSaveTo equal to CERT_STORE_SAVE_TO_FILENAME_A and

for dwSaveTo equal to CERT_STORE_SAVE_TO_FILENAME_W and

for dwSaveTo equal to CERT_STORE_SAVE_TO_FILENAME:

Opens the file, saves to it, and closes it.

The filename is passed in pvSaveToPara.

The filename is UNICODE for the "_W" option and ASCII for the "_A"option. For "_W": given, LPCWSTR pwszFilename; pvSaveToPara = (void *) pwszFilename;

For "_A": given, LPCSTR pszFilename; pvSaveToPara = (void *) pszFilename;

Note, the default (without "_A" or "_W") is UNICODE.

pvSaveToPara
Points to the "save to" data. See dwSaveTo above for usage details.
dwFlags
This parameter is not currently used and should be set to zero.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that CreateFile or WriteFile errors may be propagated to this function. This function has the following error codes:

Error code | Description
CRYPT_E_FILE_ERROR | An error occurred while writing to the file.

Example

See Example Code for Fundamental Certificate Store Operations.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertOpenStore, CertCloseStore


CertSerializeCertificateStoreElement

The CertSerializeCertificateStoreElement function serializes a certificate context's encoded certificate and an encoded representation of its properties. The result may be persisted to storage so that the certificate and properties may be retrieved at a later time.

#include <wincrypt.h>
BOOL WINAPI CertSerializeCertificateStoreElement(
  PCCERT_CONTEXT pCertContext,    // in
  DWORD dwFlags,                  // in
  BYTE *pbElement,                // out
  DWORD *pcbElement               // in, out
);

Parameters

pCertContext
Pointer to the certificate context being serialized.
dwFlags
This parameter is not currently used and should be set to zero.
pbElement
Pointer to a buffer that receives the serialized output, including the encoded certificate and possibly its properties.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbElement
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbElement parameter. When the function returns, the variable pointed to by the pcbElement parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbElement is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed

Call GetLastError to see the reason for any failures.

Example

//Serialize the data from a certificate,
//and add that data as a new certificate to a store.
// handle_error() is a function defined in a separate file.
HCERTSTORE         hStoreHandle1;
HCERTSTORE         hStoreHandle2;
PCCERT_CONTEXT     pCertContext;
BYTE*              pbElement;
DWORD              cbElement;

// Open a system certificate store.
if(hStoreHandle1 = CertOpenSystemStore(0,"MY"))
printf("The MY system store is open. Continue.\n");
else
handle_error("The first system store did not open.");
//
if(hStoreHandle2 = CertOpenSystemStore(0,"CA"))
printf("The CA system store is open. Continue.");
else
handle_error("The second system store did not open.");
//
// Retrieve the first certificate from the MY store.
if(pCertContext=CertEnumCertificatesInStore(
hStoreHandle1,
NULL))
printf("A certificate is available. Continue.\n");
else
handle_error("No certificate is available. The store may be empty.");
//
// 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 first call to the function succeeded. Continue.\n");
else
handle_error("The first call to CertSerialize failed.");
//
// Allocate memory for the serialized element.
if(pbElement = (BYTE*)malloc(cbElement))
printf("Memory has been allocated. Continue.\n");
else
handle_error("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 seralized element,
    ))
printf("The encode element has been serialized. Continue. \n");
else
handle_error("The second call to the function failed.");
//
// Add the newly created element to the store.
if(CertAddSerializedElementToStore(
    hStoreHandle2,       // Store where cert is to be added.
    pbElement ,          // The serialized element for another
                         // cert.
    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
    handle_error("The new element was not added to a store.");
//
// Free memory.
free(pbElement);
CertCloseStore(hStoreHandle1,0);
CertCloseStore(hStoreHandle2,0);
printf("The program ran without error to the end.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddSerializedElementToStore


CertSerializeCRLStoreElement

The CertSerializeCRLStoreElement function serializes a CRL context's encoded CRL and an encoded representation of its properties. The result may be persisted to storage so that the CRL and properties may be retrieved at a later time.

#include <wincrypt.h>
BOOL WINAPI CertSerializeCRLStoreElement(
  PCCRL_CONTEXT pCrlContext,     // in
  DWORD dwFlags,                 // in
  BYTE *pbElement,               // out
  DWORD *pcbElement              // in, out
);

Parameters

pCrlContext
Pointer to the CRL context being serialized.
dwFlags
This parameter is not currently used and should be set to zero.
pbElement
Pointer to a buffer that receives the serialized output, including the encoded CRL, and possibly its properties.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbElement
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbElement parameter. When the function returns, the variable pointed to by the pcbElement parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbElement is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

See example code with CertSerializeCertificateStoreElement.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddSerializedElementToStore


CertSerializeCTLStoreElement

The CertSerializeCTLStoreElement function serializes a CTL context's encoded CTL and an encoded representation of its properties. The result may be persisted to storage so that the CTL and properties may be retrieved at a later time.

#include <wincrypt.h>
BOOL WINAPI CertSerializeCTLStoreElement(
  PCCTL_CONTEXT pCtlContext,     // in
  DWORD dwFlags,                 // in
  BYTE *pbElement,               // out
  DWORD *pcbElement              // in, out
);

Parameters

pCtlContext
Pointer to the CTL context being serialized.
dwFlags
This parameter is not currently used and should be set to zero.
pbElement
Pointer to a buffer that receives the serialized output, including the encoded CTL, and possibly its properties.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbElement
Pointer to a variable that specifies the size, in bytes, of the buffer that is pointed to by pbElement parameter. When the function returns, the variable pointed to by the pcbElement parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbElement is NULL.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

See example code with CertSerializeCertificateStoreElement.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertAddSerializedElementToStore


CertSetCertificateContextProperty

The CertSetCertificateContextProperty function sets a property for the specified certificate context.

#include <wincrypt.h>
BOOL WINAPI CertSetCertificateContextProperty(
  PCCERT_CONTEXT pCertContext,     // in
  DWORD dwPropId,                  // in
  DWORD dwFlags,                   // in
  void *pvData                     // in
);

Parameters

pCertContext
Pointer to a certificate context.
dwPropId
DWORD identifying the property to be set. The value of dwPropId determines the type and content of the pvData parameter Currently defined IDs and their related pvData types are:
Property ID | pvData type
CERT_KEY_PROV_HANDLE_PROP_ID | HCRYPTPROV
CERT_KEY_PROV_INFO_PROP_ID | CRYPT_KEY_PROV_INFO
CERT_HASH_PROP_ID | CRYPT_HASH_BLOB
CERT_SHA1_HASH_PROP_ID | CRYPT_HASH_BLOB
CERT_MD5_HASH_PROP_ID | CRYPT_HASH_BLOB
CERT_KEY_CONTEXT_PROP_ID | CERT_KEY_CONTEXT
CERT_KEY_SPEC_PROP_ID | DWORD
CERT_ENHKEY_USAGE_PROP_ID | CRYPT_DATA_BLOB
CERT_CTL_USAGE_PROP_ID | CRYPT_DATA_BLOB
CERT_FRIENDLY_NAME_PROP_ID | CRYPT_DATA_BLOB
CERT_PVK_FILE_PROP_ID | CRYPT_DATA_BLOB
CERT_NEXT_UPDATE_LOCATION_PROP_ID | CRYPT_DATA_BLOB
CERT_SIGNATURE_HASH_PROP_ID | CRYPT_HASH_BLOB

The following list presents the definitions for the dwPropId types:

CERT_KEY_PROV_HANDLE_PROP_ID
A HCRYPTPROV handle for the certificate's private key is passed in pvData The hCryptProv field of the CERT_KEY_CONTEXT_PROP_ID is updated if it exists. If it does not exist, it is created with dwKeySpec initialized from CERT_KEY_PROV_INFO_PROP_ID. If the CERT_STORE_NO_CRYPT_RELEASE_FLAG is not set, the HCRYPTPROV is implicitly released either when the property is set to NULL or on the final freeing of the CERT_CONTEXT.
CERT_KEY_PROV_INFO_PROP_ID
pvData points to a CRYPT_KEY_PROV_INFO structure specifying the certificate's private key.
CERT_HASH_PROP_ID, CERT_SHA1_HASH_PROP_ID and CERT_MD5_HASH_PROP_ID
Typically, this property is implicitly set by a call to CertGetCertificateContextProperty.
CERT_KEY_CONTEXT_PROP_ID
pvData points to a CERT_KEY_CONTEXT structure specifying the certificate's private key. The CERT_KEY_CONTEXT contains both the HCRYPTPROV and dwKeySpec for the private key. See the CERT_KEY_PROV_HANDLE_PROP_ID for more information about the HCRYPTPROV field and dwFlags settings. Note that more fields may be added for this property. The cbSize field value will be adjusted accordingly. cbSize must be set to the size of CERT_KEY_CONTEXT.
CERT_KEY_SPEC_PROP_ID
pvData points to a DWORD that specifies the private key. The dwKeySpec field of the CERT_KEY_CONTEXT_PROP_ID is updated if it exists. If it does not, it is created with hCryptProv set to zero.
CERT_ENHKEY_USAGE_PROP_ID and CERT_CTL_USAGE_PROP_ID
pvData points to a CRYPT_DATA_BLOB containing an ASN.1 encoded CTL_USAGE data structure encoded using CryptEncodeObject(X509_ENHANCED_KEY_USAGE).
CERT_NEXT_UPDATE_LOCATION_PROP_ID
pvData points to a CRYPT_DATA_BLOB containing an ASN.1 encoded CERT_ALT_NAME_INFO data structure encoded using CryptEncodeObject(X509_ALTERNATE_NAME). CERT_NEXT_UPDATE_LOCATION_PROP_ID is currently used only with CTLs.
CERT_FRIENDLY_NAME_PROP_ID
pvData points to a CRYPT_DATA_BLOB, specifying the friendly name for a certificate, CRL or CTL. Inside the CRYPT_DATA_BLOB, the pbData member is a pointer to a NULL terminated unicode, wide character string, and cbData indicates the length of the string.
CERT_PVK_FILE_PROP_ID
pvData points to a CRYPT_DATA_BLOB that specifies the name of a file that contains the private key associated with the certificate's public key. Inside the CRYPT_DATA_BLOB, the pbData member is a pointer to a NULL terminated unicode, wide character string, and cbData indicates the length of the string.
CERT_SIGNATURE_HASH_PROP_ID
If a signature hash does not exist, it is computed with CryptHashToBeSigned. pvData to points to an existing or computed hash. Normally the length of the hash is 20 bytes for SHA and 16 for MD5.

Additional dwPropId types may be defined by the user using DWORD values from CERT_FIRST_USER_PROP_ID to CERT_LAST_USER_PROP_ID. For all user defined dwPropIds, pvData should point to an encoded CRYPT_DATA_BLOB.

dwFlags
The CERT_STORE_NO_CRYPT_RELEASE_FLAG can be set for the CERT_KEY_PROV_HANDLE_PROP_ID or CERT_KEY_CONTEXT_PROP_ID properties.
pvData
Pointer to a data type that is determined by the value of dwPropId. For any dwPropId, setting pvData to NULL deletes that property.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError may be called to indicate the reason for any failure. This function uses the following error code:

E_INVALIDARG
Invalid property. The ID specified was greater than 0x0000FFFF, or, for the CERT_KEY_CONTEXT_PROP_ID property, an invalid cbSize in the CERT_KEY_CONTEXT structure was specified.

Remarks

If the property already exists, then the old value is replaced.

Example

//
// Set the CERT_KEY_PROV_INFO_PROP_ID property
// for a certificate context.
HCERTSTORE          hStoreHandle;
PCCERT_CONTEXT      pCertContext;
CRYPT_KEY_PROV_INFO *pCryptKeyProvInfo;
LPWSTR              ContainerName = L"Jack Fink";
DWORD               dwPropId = CERT_KEY_PROV_INFO_PROP_ID;
DWORD               dwFlags =  CERT_STORE_NO_CRYPT_RELEASE_FLAG;

// Open a store as the source of the certificate
// that is to have a property added to it.
if(hStoreHandle = CertOpenSystemStore(0,"MY"))
printf("The MY store is open. Continue. \n");
else
handle_error("The first system store did not open.");
//
// Get a certificate from the MY store.
if(pCertContext=CertEnumCertificatesInStore(
hStoreHandle,NULL))
printf("A certificate is available. Continue.\n");
else
handle_error("No certificate was retrieved.\n\
Perhaps the store is empty.");
//
// Initalize the CRYPT_KEY_PROV_INFO data structure.
// Note: pwszContainerName and pwszProvName can be set to NULL
// to use the default container and provider.
pCryptKeyProvInfo->pwszContainerName = ContainerName ;
pCryptKeyProvInfo->pwszProvName = MS_ENHANCED_PROV_W;
pCryptKeyProvInfo->dwProvType = PROV_RSA_FULL;
pCryptKeyProvInfo->dwFlags = 0;
pCryptKeyProvInfo->cProvParam = 0;
pCryptKeyProvInfo->rgProvParam = NULL;
pCryptKeyProvInfo->dwKeySpec = AT_SIGNATURE;
//
// Set the property.
if(CertSetCertificateContextProperty(
     pCertContext,       // A pointer to the certificate
                         // where the propertiy will be set.
     dwPropId,           // An identifier of the property to be set.
                         // In this case, CERT_KEY_PROV_INFO_PROP_ID
                         // is to be set to provide a pointer with the
                         // certificate to its associated private key
                         // container.
     dwFlags,            // The flag used in this case is
                         // CERT_STORE_NO_CRYPT_RELEASE_FLAG
                         // indicating that the cryptographic
                         // context aquired should not
                         // be released when the function finishes.
     pCryptKeyProvInfo   // A pointer to a data structure that holds
                         // infomation on the private key container to
                         // be associated with this certificate.
     ))
printf("The property has been set. Continue.\n");
else
handle_error("The main function failed\n \
//
// The function worked as planned.
// Continue as desired.
printf("The program finished without errors.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertSetCRLContextProperty


CertSetCRLContextProperty

The CertSetCRLContextProperty function sets a property for the specified CRL context.

#include <wincrypt.h>
BOOL WINAPI CertSetCRLContextProperty(
  PCCRL_CONTEXT pCrlContext,    // in
  DWORD dwPropId,               // in
  DWORD dwFlags,                // in
  void *pvData                  // in
);

Parameters

pCrlContext
Pointer to the CRL context.
dwPropId
See CertSetCertificateContextProperty for the complete list of defined IDs. Normally only the following properties will be set:
CERT_HASH_PROP_ID, CERT_SHA1_HASH_PROP_ID or CERT_HASH_MD5_PROP_ID
This property is normally implicitly set by a call to CertGetCRLContextProperty. pvData points to a CRYPT_HASH_BLOB.
CERT_SIGNATURE_HASH_PROP_ID
If the hash does not exist, it is computed with CryptHashToBeSigned. pvData points to the existing or computed hash. Normally the length of the hash is 20 bytes for SHA and 16 for MD5.

For all the other PROP_IDs, pvData points to an encoded CRYPT_DATA_BLOB.

dwFlags
See CertSetCertificateContextProperty for details about setting flags.
pvData
Pointer to a data type that is determined by the value passed in dwPropId.

Important For all values of pwPropId, setting pvData to NULL deletes the property.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

GetLastError may be called to indicate the reason for any failure. This function uses the following error code:

E_INVALIDARG
Invalid property. The ID specified was greater than 0x0000FFFF, or, for the CERT_KEY_CONTEXT_PROP_ID property, an invalid cbSize in the CERT_KEY_CONTEXT structure was specified.

Remarks

If a property already exists, the old value is replaced.

Example

See CertSetCertificateContextProperty.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertSetCTLContextProperty

The CertSetCTLContextProperty function sets a property for the specified CTL context.

#include <wincrypt.h>
BOOL WINAPI CertSetCTLContextProperty(
  PCCTL_CONTEXT pCtlContext,    // in
  DWORD dwPropId,               // in
  DWORD dwFlags,                // in
  void *pvData                  // in
);

Parameters

pCtlContext
Pointer to the CTL context.
dwPropId
See CertSetCertificateContextProperty for the complete list of defined IDs. Typically only the following properties will be set:
Property ID type Definition
CERT_NEXT_UPDATE_
LOCATION_PROP_ID 		Typiclly, this property is implicitly set by a call to CertGetCTLContextProperty. pvData points to a CRYPT_DATA_BLOB containing an ASN_1 encoded CERT_ENHKEY_USAGE (encoded via CryptEncodeObject(
X509_ENHANCED_KEY_USAGE))

For all the other PROP_IDs, pvData points to an encoded CRYPT_DATA_BLOB.

dwFlags
See CertSetCertificateContextProperty for details about setting flags.
pvData
Pointer to a data type that is determined by the value passed in dwPropId.

Important Setting pvData to NULL deletes the property.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes:

Error code | Description
E_INVALIDARG | Invalid property ID. See CertSetCertificateContextProperty for details.

Remarks

If the property already exists, then, the old value is deleted and replaced.

Example

See CertSetCertificateContextProperty.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetCTLContextProperty


CertSetStoreProperty

[This is preliminary documentation and subject to change.]

The CertSetStoreProperty function sets a store property.

# include <wincrypt.h>
BOOL CertSetStoreProperty(
  HCERTSTORE hCertStore,      // in
  DWORD dwPropId,             // in
  DWORD dwFlags,              // in
  const void *pvData          // in
);

Parameters

hCertStore
Handle for the certificate store.
dwPropId
DWORD for one of a range of defined store properties. Values for user defined properties should be outside the current range of predefined context properties values. Currently, user defined pwPropId values should begin at 4096. There is one predefined store property, CERT_STORE_LOCALIZED_NAME_PROP_ID, the localized name of the store.
dwFlags
Currently unused. Should be set to 0.
pvData
The type definition for pvData depends on the dwPropId value. For CERT_STORE_LOCALIZED_NAME_PROP_ID, pvData points to a CRYPT_DATA_BLOB. The pbData member of that structure is a pointer to a NULL terminated, unicode character string. The cbData member of that structure holds the size of the string.

For all user defined dwPropId values, pvData is a pointer to an encoded PCRYPT_DATA_BLOB,

If a value already exists for the selected property, the old value is replaced.

Calling this function with pvData set to NULL deletes a property.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Remarks

Store property IDs are properties applicable to an entire store. They are not properties on an individual certificate, CRL, or CTL context. Currently, no store properties are persisted.

Example

See CertGetStoreProperty for example code.

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetStoreProperty


CertUnregisterPhysicalStore

[This is preliminary documentation and subject to change.]

The CertUnregisterPhysicalStore function removes a physical store from a specified system store collection. CertUnregisterPhysicalStore may also be used to delete the physical store.

#include <wincrypt.h>
BOOL WINAPI CertUnregisterPhysicalStore(
  const void *pvSystemStore,  // in
  DWORD dwFlags,              // in
  LPCWSTR pwszStoreName       // in
);

Parameters

pvSystemStore
Identifier of the system store collection that the physical store is to be removed from. It points to either a NULL terminated unicode string or to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure. See CertRegisterSystemStore for details on using the data structure and on prepending a ServiceName or Computer name to the system store name string.
dwFlags
The HIWORD of the dwFlags parameter is used to specify the location of the system store. See CertRegisterSystemStore for details on defined HIWORD dwFlags and prepending ServiceName, UserNames, and ComputerNames to the system store name.

The following LOWORD dwFlags are also defined and may be ORed with HIWORD flags.

CERT_SYSTEM_STORE_RELOCATE_FLAG
When this flag is set, the system store is not in its default registry location and pvSystemStore must be a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure.
CERT_STORE_DELETE_FLAG
When this flag is set, the physical store is first removed from the system store collection and is then deleted.
pwszStoreName
NULL terminated unicode string that indicates the name of the physical store.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Remarks

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

LPCWSTR pwszSystemStore= L"My";
LPCWSTR pwszPStore=L"TestPStore";
DWORD dwFlags=CERT_SYSTEM_STORE_CURRENT_USER |CERT_STORE_DELETE_FLAG ;
//
if(CertUnregisterPhysicalStore(
pwszSystemStore,
dwFlags,
pwszPStore
            ))
printf("Store %S has been unregistered. \n", pwszPStore);
else
printf("The unregister operation failed.\n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertRegisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumSystemStore, CertEnumPhysicalStore


CertUnregisterSystemStore

[This is preliminary documentation and subject to change.]

The CertUnregisterSystemStore function unregisters a specified system store.

#include <wincrypt.h>
BOOL WINAPI CertUnregisterSystemStore(
  const void *pvSystemStore,   // in
  DWORD dwFlags                //  in
);

Parameters

pvSystemStore
Identifier of the system store to be unregistered. Points to either a NULL terminated unicode string or to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure. See CertRegisterSystemStore for details on using the data structure and on prepending a ServiceName or Computer name to the system store name string.
dwFlags
The HIWORD of the dwFlags parameter is used to specify the location of the system store. See CertRegisterSystemStore for details on defined HIWORD dwFlags and prepending ServiceName, UserNames, and ComputerNames to the system store name.

The following LOWORD dwFlags are also defined and may be ORed with HIWORD flags.

CERT_SYSTEM_STORE_RELOCATE_FLAG
When this flag is set, the system store is not in its default registry location and pvSystemStore must be a pointer to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure.
CERT_STORE_DELETE_FLAG
When this flag is set the system store is deleted after it has been unregistered.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Remarks

To access a remote store, the Security Permissions in the registry keys on that remote computer must be set to allow access. For more information on setting Security Permissions in an NT registry, see MDSN Article ID Q155363. For information on what to do to enable remote administration on a Win95 registry.

Example

LPCWSTR pwszSystemName=L"TempSystemStore";
DWORD   dwFlags=CERT_SYSTEM_STORE_CURRENT_USER;
//
if(CertUnregisterSystemStore(
pwszSystemName,
dwFlags
      ))
printf("System store %S has been unregistered.\n",pwszSystemName);
else
printf("The system store was not unregistered.\n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertRegisterSystemStore, CertRegisterPhysicalStore, CertUnregisterPhysicalStore, CertEnumSystemStoreLocation, CertEnumSystemStore, CertEnumPhysicalStore


CertVerifySubjectCertificateContext

The CertVerifySubjectCertificateContext function performs the enabled verification checks on the subject certificate by using the issuer.

#include <wincrypt.h>
BOOL WINAPI CertVerifySubjectCertificateContext(
  PCCERT_CONTEXT pSubject,  // in
  PCCERT_CONTEXT pIssuer,   // in, optional
  DWORD *pdwFlags           // in/out
);

Parameters

pSubject
Pointer to the subject context.
pIssuer
Pointer to an issuer context. When checking just the CERT_STORE_TIME_VALIDITY_FLAG, pIssuer may be NULL.
pdwFlags
The following flags can be set in *pdwFlags to enable verification checks on the subject certificate:
CERT_STORE_REVOCATION_FLAG (0x00000004)
Checks whether the subject certificate is on the issuer's revocation list.
CERT_STORE_SIGNATURE_FLAG (0x00000001)
Uses the public key in the issuer's certificate to verify the signature on the subject certificate.
CERT_STORE_TIME_VALIDITY_FLAG (0x00000002)
Gets the current time and verifies that it is within the subject certificate's validity period.

If an enabled verification check succeeds, its flag is set to zero. If it fails, then its flag is set upon return.

If CERT_STORE_REVOCATION_FLAG was enabled and the issuer doesn't have a CRL in the store, then CERT_STORE_NO_CRL_FLAG is set in addition to the CERT_STORE_REVOCATION_FLAG.

Return Values

For a verification check failure, TRUE is still returned. FALSE is returned only when a bad parameter is passed in.

Call GetLastError to see the reason for any failures. This function has the following error code:

Error code | Description
E_INVALIDARG | Unsupported bit was set in *pdwFlags. Any combination of: CERT_STORE_SIGNATURE_FLAG, CERT_STORE_TIME_VALIDITY_FLAG, or CERT_STORE_REVOCATION_FLAG maybe set. If pIssuer argument is NULL, only CERT_STORE_TIME_VALIDITY_FLAG may be set.

Remarks

The hexadecimal value of the flags may be combined together with a bitwise OR operation in order to enable multiple verifications. For example, to enable both signature and time validity, the value CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG ( which is equal to 0x00000003) would be placed in the double word *pdwFlags as an "in" parameter. If CERT_STORE_SIGNATURE_FLAG verification succeeded, but CERT_STORE_TIME_VALIDITY_FLAG verification failed, *pdwFlags would be set to the value of CERT_STORE_TIME_VALIDITY_FLAG (which is equal to 0x00000002), as an "out" parameter, when the function returns.

Example

// CertVerifySubjectCertificateContext
// Check a certificate for all verification checks.
// handle_error() is a function defined in a separate file.
HCERTSTORE hSubjectStoreHandle;  // The store that is the source of
// the subject certificate.
HCERTSTORE hIssuerStoreHandle;   // The store that is the source of
                                 // the issuer certificate.
PCCERT_CONTEXT pSubjectCert;
PCCERT_CONTEXT pIssuerCert;
DWORD dwFlags=0;
//
// Set dwFlags to check for three validity conditions.
dwFlags = CERT_STORE_REVOCATION_FLAG|
CERT_STORE_SIGNATURE_FLAG|
CERT_STORE_TIME_VALIDITY_FLAG;
//
// Open a store and get a subject cert.
if(hSubjectStoreHandle = CertOpenSystemStore(0,"MY"))
printf("The MY store is open. Continue.\n");
else
handle_error("The MY store did not open.");
//
// Open a second store and get an issuer cert.
if(hIssuerStoreHandle = CertOpenSystemStore(0,"CA"))
printf("The CA store is open. Continue. \n");
else
handle_error("The CA store did not open.");
//
// Get a subject cert from the MY store.
if(pSubjectCert=CertEnumCertificatesInStore(
hSubjectStoreHandle,NULL))
printf("A subject certificate is available. Continue.\n");
else
handle_error("A subject certificate was not retrieved.\n\
Perhaps the store is empty.");
if(pIssuerCert=CertEnumCertificatesInStore(
hIssuerStoreHandle,NULL))
printf("An issuer certificate is available. Continue.\n");
else
handle_error("The issuer certificate was not retrieved.\n\
perhaps the store is empty.");
//
// Verify the subject certificate.
if(CertVerifySubjectCertificateContext(
     pSubjectCert,     // Pointer to the subject certificate.
     pIssuerCert,      // Pointer to an issuer certificate.
     &dwFlags          // dwFlags indicating the validity
                       // conditions to be checked.
    ))
printf("Verify functioned correctly. Continue.\n");
else
handle_error("CertVerify did not function correctly.");
//
// Check the returned flags to see if the certificate passed
// The verification checks.
if (dwFlags > 0)
{
// One or more checks did not pass. Determine which checks failed.
printf("dwFlags value is %d \n",dwFlags);
if ((dwFlags & CERT_STORE_REVOCATION_FLAG) > 0)
printf("The revocation check failed.\n");
if ((dwFlags & CERT_STORE_SIGNATURE_FLAG) > 0 )
printf("The signature check failed.\n");
if ((dwFlags & CERT_STORE_TIME_VALIDITY_FLAG) > 0 )
printf("The time validity check failed.\n");
}
else
printf("The certificate passed all validity checks.\n");
//
printf("The program ran to completion without error.\n");

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetIssuerCertificateFromStore


Certificate Helper Functions

These Win32® functions help you to manipulate certificates. You can use these functions to perform such tasks as comparing, converting, signing, hashing, and verifying certificate data.

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CertAddEnhancedKeyUsageIdentifier | Adds the usage identifier to the certificate's enhanced key usage property.
CertAlgIdToOID | Converts the CSP algorithm identifier to the ASN.1 Object Identifier string.
CertCompareCertificate | Compares two certificates to determine whether they are identical.
CertCompareCertificateName | Compares two certificate names to determine whether they are identical.
CertCompareIntegerBlob | Compares two integer blobs.
CertComparePublicKeyInfo | Compares two public keys to determine whether they are identical.
CertFindAttribute | Finds the first attribute identified by its Object Identifier.
CertFindExtension | Finds the first extension identified by its Object Identifier.
CertFindRDNAttr | Finds the first RDN attribute identified by its Object Identifier in the name list of the Relative Distinguished Names.
CertFindSubjectInCTL | Attempts to find the specified subject in the CTL.
CertGetEnhancedKeyUsage | Gets the intended key usage extension or property from the certificate.
CertGetIntendedKeyUsage | Gets the intended key usage bytes from the certificate.
CertGetNameString | Gets the subject or issuer name from the certificate and converts it to a null terminated character string.
CertGetPublicKeyLength | Gets the public/private key's bit length from the public key blob.
CertIsRDNAttrsInCertificateName | Compares the attributes in the certificate name with the specified RDN's array of attributes to determine whether all attributes are included there.
CertNameToStr | Converts a certificate name blob to a zero-terminated character string.
CertOIDToAlgId | Converts the ASN.1 Object Identifier string to the CSP algorithm identifier.
CertRDNValueToStr | Converts a Name Value to a zero-terminated character string.
CertRemoveEnhancedKeyUsageIdentifier | Removes the usage identifier from the certificate's enhanced key usage property.
CertSetEnhancedKeyUsage | Sets the intended key usage property for the certificate.
CertStrToName | Converts a NULL-terminated X500 string to an encoded certificate name.
CertVerifyCRLRevocation | Verifies that the subject certificate is not on the CRL.
CertVerifyCRLTimeValidity | Verifies the time validity of a CRL.
CertVerifyCTLUsage | Verifies that a subject is trusted for the specified usage by finding a signed and time valid CTL with the usage identifiers and containing the subject.
CertVerifyRevocation | Verifies the array of contexts for revocation.
CertVerifyTimeValidity | Verifies the time validity of a certificate.
CertVerifyValidityNesting | Verifies that the subject's time validity nests within the issuer's time validity.
CryptAcquireCertificatePrivateKey | Acquires a HCRYPTPROV handle and dwKeySpec for the specified certificate context.
CryptExportPublicKeyInfo | Exports the public key information associated with the provider's corresponding private key.
CryptExportPublicKeyInfoEx | Exports the public key information associated with the provider's corresponding private key. The main difference from CryptExportPublicKeyInfo is that the user can specify the public key algorithm, overriding the default provided by the CSP.
CryptFindCertificateKeyProvInfo | Enumerates the cryptographic providers and their containers to find the private key corresponding to the certificate's public key.
CryptFindLocalizedName | Finds the localized name for the specified name, such as the "Root" system store name.
CryptHashCertificate | Hashes the encoded content.
CryptHashPublicKeyInfo | Computes the hash of the encoded public key information.
CryptHashToBeSigned | Computes the hash of the "to be signed" information in the encoded signed content (CERT_SIGNED_CONTENT_INFO).
CryptImportPublicKeyInfo | Converts and imports the public key information into the provider and returns a handle to the public key.
CryptImportPublicKeyInfoEx | Converts and imports the public key information into the provider and returns a handle to the public key. Additional parameters (over those specified by CryptImportPublicKeyInfo) that can be used to override defaults are provided to supplement the CERT_PUBLIC_KEY_INFO.
CryptSignAndEncodeCertificate | Encodes the "to be signed" information. Signs this encoded information. Encodes the resulting signed encoded information.
CryptSignCertificate | Signs the "to be signed" information in the encoded signed content.
CryptVerifyCertificateSignature | Verifies the signature of a subject certificate, certificate request list (CRL), or certificate request by using the public key information.


CertAddEnhancedKeyUsageIdentifier

The CertAddEnhancedKeyUsageIdentifier function adds the usage identifier to the certificate's enhanced key usage property.

#include <wincrypt.h>
BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(
  PCCERT_CONTEXT pCertContext, // in
  LPCSTR pszUsageIdentifier    // in
);

Parameters

pCertContext
Specifies the certificate for which the usage identifier is to be added.
pszUsageIdentifier
Specifies the usage identifier to add.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

// EXAMPLE CODE FOR USING CertAddEnhancedKeyUsageIdentifier
// add the usage identifier to the certificate's enhanced key usage
// property

// hash a certificate for which a certificate context has already
// been obtained (pCertContext).
// Set up the variables.
PCCERT_CONTEXT  pCertContext;          // Initialized elsewhere
LPCSTR          pszUsageIdentifier = szOID_RSA_RC4; // in
BOOL            Return;

Return = CertAddEnhancedKeyUsageIdentifier(
          pCertContext,                // the certificate
          pszUsageIdentifier);         // the identifier to add
if (Return) {
 cout<< "function succeeded- usage identifier added "<< endl;
}
else {
 cout<< "function failed "<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertAlgIdToOID

The CertAlgIdToOID function converts the Microsoft® CryptoAPI algorithm identifier (ALG_ID) to the ASN.1 Object Identifier string.

#include <wincrypt.h>
LPCSTR WINAPI CertAlgIdToOID(
  DWORD dwAlgId            // in
);

Parameters

dwAlgId
The dwAlgId to be converted to an OID.

Return Values

Returns NULL if there isn't an Object Identifier string corresponding to the algorithm identifier.

Example

// EXAMPLE CODE FOR USING CertAlgIdToOID() to
// convert the CALG_SHA algorithm identifier to an
// Object Identifier string.

// Set up the variables.
LPCSTR pszObjID;

pszObjID= CertAlgIdToOID(CALG_SHA);

if (pszObjID == NULL)
   printf("No object identifier string correlates to the ALG_ID. \n");
else
   // Print the object identifier returned.
   printf("%s", pszObjID );

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertCompareCertificate

The CertCompareCertificate function compares two certificates to determine whether they are identical.

#include <wincrypt.h>
BOOL WINAPI CertCompareCertificate(
  DWORD dwCertEncodingType,  // in
  PCERT_INFO pCertId1,       // in
  PCERT_INFO pCertId2        // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pCertId1
A pointer to the CERT_INFO for the first certificate in the comparison.
pCertId2
A pointer to the CERT_INFO for the second certificate in the comparison.

Return Values

TRUE if the certificates are identical.

Example

// EXAMPLE CODE FOR USING CertCompareCertificate() to
// compare two certificates to determine whether they are identical.

// Assume that the application has a pointer to both certificates to
// compare (pCertId1, pCertId2) and that X509_ASN_ENCODING was used to
// encode the certificates.

// Set up the variables.
PCERT_INFO pCertId1, pCertId2; // Initialized elsewhere
BOOL Return;

Return = CertCompareCertificate(
            X509_ASN_ENCODING, pCertId1, pCertId2);

if (Return == TRUE) {
    // The certificates are identical, continue as desired.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertCompareCertificateName


CertCompareCertificateName

The CertCompareCertificateName function compares two certificate names to determine whether they are identical.

#include <wincrypt.h>
BOOL WINAPI CertCompareCertificateName(
  DWORD dwCertEncodingType,     // in
  PCERT_NAME_BLOB pCertName1,   // in
  PCERT_NAME_BLOB pCertName2    // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pCertName1
A pointer to the CERT_NAME_BLOB for the first name in the comparison. See BLOB Structure.
pCertName2
A pointer to the CERT_NAME_BLOB for the second name in the comparison.

Return Values

TRUE if the names are identical.

Example

// EXAMPLE CODE FOR USING CertCompareCertificateName() to
// compare two certificate names to determine whether they are identical.

// Assume that the application has a pointer to both certificate names to
// compare (pCertName1, pCertName2) and that X509_ASN_ENCODING was
// used to encode the certificate names.

// Set up the variables.
PCERT_NAME_BLOB pCertName1, pCertName2; // Initialized elsewhere
BOOL Return;

Return = CertCompareCertificateName(
            X509_ASN_ENCODING, pCertName1, pCertName2);

if (Return == TRUE) {
    // The certificate names are identical, continue as desired.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertCompareCertificate


CertCompareIntegerBlob

The CertCompareIntegerBlob function compares two integer blobs to determine whether they are identical. Before doing the comparison, leading bytes with a value of 0x00 are removed from a positive number (by positive, it is meant that the most significant bit in the next nonzero byte is not set). Leading bytes with a value of 0xFF are removed from a negative number (by negative, it is meant that the most significant bit in the next non 0xFF byte is set). This produces the unique representation of that integer. For instance:

FFFFFFAB reduces to AB (shown in below example)
FF23 reduces to FF23
007F reduces to 7F
00000080 reduces to 0080

Multiple byte integers are treated as Little Endian. The least significant byte is pbData(0). The most significant byte is pbData(cbData - 1).

#include <wincrypt.h>
BOOL WINAPI CertCompareIntegerBlob(
  PCRYPT_INTEGER_BLOB pInt1    // in
  PCRYPT_INTEGER_BLOB pInt2    // in
);

Parameters

pInt1
A pointer to the first integer blob in the comparison.
pInt2
A pointer to the second integer blob in the comparison.

Return Values

Returns TRUE if the unique representation of the integer blobs are identical.

Example

// EXAMPLE CODE FOR USING CertCompareIntegerBlob() to
// compare two integer blobs to determine whether they are identical.

// Assume that the application has a pointer to both integer blobs to
// compare (pInt1, pInt2).

// Set up the variables.
BOOL                 Return;
PCRYPT_INTEGER_BLOB  pInt1, pInt2;

// Initialize the blobs.
BYTE blob1data[4] = {0xFF, 0xFF, 0xFF, 0xAB};
BYTE blob2data[1] = {0xAB};
pInt1->pbData = (BYTE*)&blob1data;
pInt1->cbData = sizeof(blob1data);
pInt2->pbData = (BYTE*)&blob2data;
pInt2->cbData = sizeof(blob2data);

Return = CertCompareIntegerBlob(
            pInt1, pInt2);

if (Return == TRUE) {
    // For this example the integer blobs are identical,

    // However, note that FALSE would have been returned if
    // BYTE blob2data[2] = {0x00, 0xAB}; had been used.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertComparePublicKeyInfo

The CertComparePublicKeyInfo function compares two public keys to determine whether they are identical. The public key blobs must be in their encoded representation.

#include <wincrypt.h>
BOOL WINAPI CertComparePublicKeyInfo(
  DWORD dwCertEncodingType,           // in
  PCERT_PUBLIC_KEY_INFO pPublicKey1,  // in
  PCERT_PUBLIC_KEY_INFO pPublicKey2   // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pPublicKey1
A pointer to the CERT_PUBLIC_KEY_INFO for the first public key in the comparison.
pPublicKey2
A pointer to the CERT_PUBLIC_KEY_INFO for the second public key in the comparison.

Return Values

TRUE if the public keys are identical.

Example

// EXAMPLE CODE FOR USING CertComparePublicKeyInfo() to
// compare two public keys to determine whether they are identical.

// Assume that the application has a pointer to both public keys to
// compare (pPublicKey1, pPublicKey2) and that X509_ASN_ENCODING was used.

// Set up the variables.
PCERT_PUBLIC_KEY_INFO pPublicKey1, pPublicKey2; // Initialized elsewhere
BOOL Return;

Return = CertComparePublicKeyInfo(
            X509_ASN_ENCODING, pPublicKey1, pPublicKey2);

if (Return == TRUE) {
    // The public keys are identical, continue as desired.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertFindAttribute

The CertFindAttribute function finds the first attribute in the CRYPT_ATTRIBUTE array, as identified by its Object Identifier. Processing a decoded certificate request is one way this function gets used. From the decoded certificate request, a CERT_REQUEST_INFO structure is derived. From that structure the rgAttribute array is retrieved and passed to this function in rgAttr[]. Then this function can determine whether a particular attribute is in the array, and if so, return a pointer to it.

#include <wincrypt.h>
PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(
  LPCSTR pszObjId,           // in
  DWORD cAttr,               // in
  CRYPT_ATTRIBUTE rgAttr[ ]  // in
);

Parameters

pszObjId
A pointer to the Object Identifier to use in the search.
cAttr
The number of attributes in rgAttr[].
rgAttr[]
The array of attributes.

Return Values

Returns a pointer to the attribute, if one is found. Otherwise, NULL is returned.

Example

// EXAMPLE CODE FOR USING CertFindAttribute
// Finds the first attribute in the CRYPT_ATTRIBUTE
// array, as identified by its Object Identifier.

// Set up the variables.
LPCSTR pszObjId = szOID_RSA_RC4;    // Object identifier
DWORD cAttr = 128;                  // # of attributes
CRYPT_ATTRIBUTE rgAttr[128];        // Initialized elsewhere
CRYPT_ATTRIBUTE * pResult;          // Pointer to returned attribute

pResult = CertFindAttribute(
            pszObjId,   // in - Pointer of object identifier
            cAttr,      // in - # of attributes in the array
            rgAttr);    // in - The array of attributes

if (!&pResult) {
  cout<< "no attribute found "<< endl;
}
else {
  cout<< "attribute found at "<< pResult<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindExtension, CertFindRDNAttr


CertFindExtension

The CertFindExtension function finds the first extension in the CERT_EXTENSION array, as identified by its Object Identifier. Processing a decoded certificate is one way this function gets used. From the decoded certificate, a CERT_INFO structure is derived. From that structure the rgExtension array is retrieved and passed to this function in rgExtensions[]. Then this function can determine whether a particular extension is in the array, and if so, return a pointer to it.

#include <wincrypt.h>
PCERT_EXTENSION WINAPI CertFindExtension(
  LPCSTR pszObjId,                // in
  DWORD cExtensions,              // in
  CERT_EXTENSION rgExtensions[ ]  // in
);

Parameters

pszObjId
A pointer to the Object Identifier to use in the search.
cExtensions
The number of extensions in rgExtensions[].
rgExtensions[]
The array of extensions.

Return Values

Returns a pointer to the extension, if one is found. Otherwise, NULL is returned.

Example

// EXAMPLE CODE FOR USING CertFindExtension.
// Finds the first extension in the CERT_EXTENSION
// array, as identified by its Object Identifier.

// Set up the variables.
LPCSTR pszObjId = szOID_RSA_RC4; // Object identifier
DWORD cExtensions = 128;         // # of extensions
CERT_EXTENSION rExtensions[128]; // Array of extensions
CERT_EXTENSION * pResult;        // Pointer to the returned extension

pResult = CertFindExtension(
            pszObjId,       // in - Pointer to object identifier
            cExtensions,    // in - # of extensions in the array
            rExtensions);   // in - The array of attributes

if (!&pResult) {
  cout<< "no extension found "<< endl;
}
else {
  cout<< "extension found at "<< pResult<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindAttribute, CertFindRDNAttr


CertFindRDNAttr

The CertFindRDNAttr function finds the first RDN attribute identified by its Object Identifier in the name list of the Relative Distinguished Names.

#include <wincrypt.h>
PCERT_RDN_ATTR WINAPI CertFindRDNAttr(
  LPCSTR pszObjId,       // in
  PCERT_NAME_INFO pName  // in
);

Parameters

pszObjId
A pointer to the Object Identifier to use in the search.
pName
A pointer to the name list of the Relative Distinguished Names.

Return Values

Returns a pointer to the attribute, if one is found. Otherwise, NULL is returned.

Example

// EXAMPLE CODE FOR USING CertFindRDNAttr() to
// find the first RDN attribute identified by its Object Identifier
// in the name list of the Relative Distinguished Names.

// Assume that a pointer to the Object Identifier to use in the
// search (pszObjId) is already known and that a pointer to the name
// list of the Relative Distinguished Names to search (pName) is
// already known.

// Set up the variables.
LPCSTR pszObjId;           // Initialized elsewhere
PCERT_NAME_INFO pName;     // Initialized elsewhere
PCERT_RDN_ATTR pAttribute;

pAttribute = CertFindRDNAttr(pszObjId, pName);

if (pAttribute != NULL) {
    // Use the found RDN attribute as desired
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindAttribute, CertFindExtension


CertFindSubjectInCTL

The CertFindSubjectInCTL function attempts to find the specified subject in the CTL. A subject can be identified by either its certificate context or any unique identifier such as its SHA1 hash.

#include <wincrypt.h>
PCTL_ENTRY WINAPI CertFindSubjectInCTL(
  DWORD dwEncodingType,       // in
  DWORD dwSubjectType,        // in
  void *pvSubject,            // in
  PCCTL_CONTEXT pCtlContext,  // in
  DWORD dwFlags               // in
);

Parameters

dwEncodingType
The type of encoding used. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwSubjectType
For CTL_CERT_SUBJECT_TYPE, pvSubject points to a CERT_CONTEXT. The CTL's SubjectAlgorithm is examined to determine the representation of the subject's identity. Initially, only SHA1 or MD5 hash will be supported. The appropriate hash property is obtained from the CERT_CONTEXT.

For CTL_ANY_SUBJECT_TYPE, pvSubject points to the CTL_ANY_SUBJECT_INFO structure which contains the SubjectAlgorithm to be matched in the CTL and the SubjectIdentifer to be matched in one of the CTL entries.

The dwEncodingType isn't used for either of the above values for dwSubjectType.

pvSubject
Depends on the dwSubjectType . See dwSubjectType for details.
pCtlContext
A pointer to the CTL_CONTEXT that is being searched.
dwFlags
The flag values. dwFlags currently does not have any defined flags and must be set to zero for future compatibility.

Return Values

Returns the entry, if it is found. If it is not found, it returns NULL.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_NOT_FOUND | Subject not found in CTL.
E-INVALIDARG | The dwSubjectType wasn't either CTL_CERT_SUBJECT_TYPE or CTL_ANY_SUBJECT_TYPE.
NTE_BAD_ALGID | The CTL's SubjectAlgorithm member didn't map to either SHA1 or MD5.

Remarks

The certificate's hash or the CTL_ANY_SUBJECT_INFO's SubjectIdentifier is used as the key in searching the subject entries. A binary memory comparison is done between the key and the entry's SubjectIdentifer.

Example

// EXAMPLE CODE FOR USING CertFindSubjectInCTL. Finds
// the subject in the CTL. The subject can be identified
// by its certificate context or unique identifier.
// Assume a pointer to the CERT_ANY_SUBJECT_INFO and a
// pointer to the CTL_CONTEXT is already known.

// Set up the variables.
DWORD dwEncodingType = X509_ASN_ENCODING;   // Type of encoding
DWORD dwSubjectType = CTL_ANY_SUBJECT_TYPE; // Subject type
CTL_ANY_SUBJECT_INFO *pvSubject;            // Initialized elsewhere
PCCTL_CONTEXT pCtlContext;                  // Initialized elsewhere
DWORD dwFlags = 0;                          // Flag value
PCTL_ENTRY pResult;                         // Pointer to the returned
                                            // subject

pResult = CertFindSubjectInCTL(
            dwEncodingType, // in - dwEncoding Type isn't used for
                            //   for this dwSubjectType
            dwSubjectType,  // in - CTL_ANY_SUBJECT_TYPE
            pvSubject,      // in - points to CTL_ANY_SUBJECT_INFO
            pCtlContext,    // in - points to CTL_CONTEXT to be
                            //   searched
            dwFlags);       // in - dwFlags set to 0

if (!pResult) {             // NULL- no entry found
  cout<< "no entry found "<< endl
      << "error code = "<< GetLastError ()<< endl;
}
else {
  cout<< "entry is "<< &pResult<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 95 OSR2 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CTL_CONTEXT, CertFindCTLInStore


CertGetEnhancedKeyUsage

The CertGetEnhancedKeyUsage function gets the enhanced key usage extension or property from the certificate.

#include <wincrypt.h>
BOOL WINAPI CertGetEnhancedKeyUsage(
  PCCERT_CONTEXT pCertContext,    // in
  DWORD dwFlags                   // in
  PCERT_ENHKEY_USAGE pUsage       // out
  DWORD *pcbUsage                 // in/out
);

Parameters

pCertContext
A pointer to the specified certificate.
dwFlags
If the CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG is set, then, only get the extension.

If the CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG is set, then, only get the property.

pUsage
Pointer to a buffer that receives the enhanced key usage.

This parameter can be NULL to set the size of the key usage for memory allocation purposes. For more information, see the "Common In/Out Parameter Conventions" section at the beginning of this Reference.

pcbUsage
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pUsage parameter. When the function returns, the variable pointed to by the pcbUsage parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pUsage is NULL.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

// EXAMPLE CODE FOR USING CertGetEnhancedKeyUsage.
// To get and print the intended key usage bytes from
// a certificate. Assume that the pointer to the
// certificate (pCertContext) is already known.

// Set up the variables.
PCCERT_CONTEXT pCertContext;// Initialized elsewhere
DWORD dwFlags = CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG;
                            // Extension only
PCERT_ENHKEY_USAGE pUsage;  // Initialized elsewhere
DWORD cbUsage = 0;          // Size of key (in bytes)
BOOL fResult;               // Returns TRUE if function succeeded
                            //   FALSE if function failed

// Function called the first time to get
// the size of cbUsage - allocate memory
fResult = CertGetEnhancedKeyUsage(
            pCertContext,
            dwFlags,
            NULL,          // NULL on first call
            &cbUsage);     // in/out - Size of enhanced key usage

if (!fResult) {            // FALSE
  cout<< "first call to CertGetEnhancedKeyUsage failed"<< endl;
}
else {                     // TRUE
  cout<< "first call to CertGetEnhancedKeyUsage successful"<< endl;
  pUsage = (PCERT_ENHKEY_USAGE)malloc(cbUsage);
  cout<< "memory allocated"<< endl;
}

// Function call to get usage extension or property.
fResult = CertGetEnhancedKeyUsage(
            pCertContext,  // in - Pointer to the certificate
            dwFlags,       // in - Extension only flag
            pUsage,        // out- Pointer to enhanced key usage
            &cbUsage);     // in/out - Size of enhanced key usage

if (!fResult) {            // FALSE
  cout<< "function failed "<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {                     // TRUE
  cout<< "function succeeded "<< endl
      << "extension/ property = "<< dwFlags<< endl
      << "enhanced key usage size = "<< &cbUsage<< endl;
}
free (pUsage);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertSetEnhancedKeyUsage


CertGetIntendedKeyUsage

The CertGetIntendedKeyUsage function gets the intended key usage bytes from the certificate. The intended key usage may be in either the szOID_KEY_USAGE ("2.5.29.15") or szOID_KEY_ATTRIBUTES ("2.5.29.2") extension.

#include <wincrypt.h>
BOOL WINAPI CertGetIntendedKeyUsage(
  DWORD dwCertEncodingType,  // in
  PCERT_INFO pCertInfo,      // in
  BYTE *pbKeyUsage,          // out
  DWORD cbKeyUsage           // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pCertInfo
A pointer to the specified certificate.
pbKeyUsage
A pointer to the intended key usage. Bit values are shown in a table for IntendedKeyUsage in CERT_KEY_ATTRIBUTES_INFO.
cbKeyUsage
The size, in bytes, of the intended key usage. Currently, the intended key usage occupies only 1 byte of data.

Return Values

If the certificate doesn't have any intended key usage bytes, FALSE is returned and *pbKeyUsage is zeroed. Otherwise, TRUE is returned and up to cbKeyUsage number of bytes are copied into *pbKeyUsage. Any remaining bytes not copied are zeroed.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note to get the OSS error, subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.

Example

// EXAMPLE CODE FOR USING CertGetIntendedKeyUsage() to get and print
// the intended key usage bytes from a certificate.

// Assume that a pointer to the certificate (pCertInfo) for which
// the intended key usage bytes are being retrieved is already known,
// that a pointer to the buffer (pbKeyUsage) to copy the intended
// key usage bytes to is already known, and that the type of encoding
// used on the certificate is X509_ASN_ENCODING.

// Set up the variables.
PCERT_INFO pCertInfo;  // Initialized elsewhere
BYTE  KeyUsageBits;    // Intended key usage bits copied to here.
DWORD cbKeyUsageByteCount = 1; // 1 byte will be copied to *pbKeyUsage
BOOL Return;

Return = CertGetIntendedKeyUsage(
            X509_ASN_ENCODING, pCertInfo,
            &KeyUsageBits, cbKeyUsageByteCount);

if (Return == TRUE) {

    // Print the intended key usages for the certificate.

    if (KeyUsageBits & CERT_DATA_ENCIPHERMENT_KEY_USAGE ==
                       CERT_DATA_ENCIPHERMENT_KEY_USAGE)
    printf("CERT_DATA_ENCIPHERMENT_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_DIGITAL_SIGNATURE_KEY_USAGE ==
                       CERT_DIGITAL_SIGNATURE_KEY_USAGE)
    printf("CERT_DIGITAL_SIGNATURE_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_KEY_AGREEMENT_KEY_USAGE ==
                       CERT_KEY_AGREEMENT_KEY_USAGE)
    printf("CERT_KEY_AGREEMENT_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_KEY_CERT_SIGN_KEY_USAGE ==
                       CERT_KEY_CERT_SIGN_KEY_USAGE)
    printf("CERT_KEY_CERT_SIGN_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_KEY_ENCIPHERMENT_KEY_USAGE ==
                       CERT_KEY_ENCIPHERMENT_KEY_USAGE)
    printf("CERT_KEY_ENCIPHERMENT_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_NON_REPUDIATION_KEY_USAGE ==
                       CERT_NON_REPUDIATION_KEY_USAGE)
    printf("CERT_NON_REPUDIATION_KEY_USAGE allowed\n");

    if (KeyUsageBits & CERT_OFFLINE_CRL_SIGN_KEY_USAGE ==
                       CERT_OFFLINE_CRL_SIGN_KEY_USAGE)
    printf("CERT_OFFLINE_CRL_SIGN_KEY_USAGE allowed\n");

}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertGetNameString

The CertGetNameString function gets the subject or issuer name from the certificate and converts it to a null terminated character string.

#include <wincrypt.h>
DWORD WINAPI CertGetNameString(
  PCCERT_CONTEXT pCertContext,    // in
  DWORD dwType,                   // in
  DWORD dwFlags,                  // in
  void *pvTypePara,               // in
  LPTSTR pszNameString,           // out/optional
  DWORD cchNameString             // in
);

Parameters

pCertContext
A pointer to the specified certificate context to be converted.
dwType
CERT_NAME_EMAIL_TYPE
If the certificate has a Subject Alternative Name extension (for issuer, Issuer Alternative Name), searches for first rfc822Name choice. If the rfc822Name choice isn't found in the extension, searches the Subject Name field for the Email OID, "1.2.840.113549.1.9.1". If the rfc822Name or Email OID is found, returns the string. Otherwise, returns an empty string (returned character count is 1). pvTypePara not used and should be set to NULL.
CERT_NAME_RDN_TYPE
Converts the Subject Name blob by calling CertNameToStr. pvTypePara points to a DWORD containing the dwStrType passed to CertNameToStr. If the Subject Name field is empty and the certificate has a Subject Alternative Name extension, searches for and converts the first directory Name choice from CertNameToStr.
CERT_NAME_ATTR_TYPE
pvTypePara points to the Object Identifier specifying the name attribute to be returned. For example, to get the CN, pvTypePara = szOID_COMMON_NAME ("2.5.4.3"). Searches the Subject Name field for the attribute. If the Subject Name field is empty and the certificate has a Subject Alternative Name extension, checks for the first directoryName choice and searches it.
CERT_NAME_SIMPLE_DISPLAY_TYPE
Iterates through the following list of name attributes and searches the Subject Name and then the Subject Alternative Name extension for the first occurrence of:

szOID_COMMON_NAME ("2.5.4.3")

szOID_ORGANIZATIONAL_UNIT_NAME ("2.5.4.11")

szOID_ORGANIZATION_NAME ("2.5.4.10")

szOID_RSA_emailAddr ("1.2.840.113549.1.9.1")

pvTypePara not used and should be set to NULL.

If none of the above attributes is found, then searches the Subject Alternative Name extension for a rfc822Name choice. If still no match, then, returns the first attribute. Note, like CERT_NAME_ATTR_TYPE, searches the RDNs in reverse order.

dwFlags
CERT_NAME_ISSUER_FLAG
If this flag is set, gets the issuer's name. Otherwise, gets the subject's name.
CERT_NAME_DISABLE_IE4_UTF8_FLAG
By default, CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as 8 bit characters. If this flag is set, skips the initial attempt to decode the value as UTF8, and decodes the value as 8 bit characters.
pvTypePara
Pointer to the a DWORD containing the dwStrType, or Object Identifier specifying the name attribute. See dwType.
pszNameString
Address for the returned string. If pszNameString != NULL && cchNameString != 0, returned pszNameString is always NULL terminated.
cchNameString
Size, in characters, allocated for the returned string. The size must include the terminating NULL character.

Return Values

Returns the number of characters converted, including the terminating zero character. If pszNameString is NULL or cchNameString is zero, returns the required size of the destination string (including the terminating null character). If the specified name type isn't found, returns an empty string with a returned character count of 1.

Example

// EXAMPLE CODE FOR USING CertGetNameString().
// Assume that a pointer to the certificate (pCertContext) is already
// known.
// Set up the variables.
PCCERT_CONTEXT pCertContext;  // Pointer to the specified certificate
                              //   Initialized elsewhere
DWORD dwType = CERT_NAME_EMAIL_TYPE;
                              // Type of CERT_NAME
DWORD dwFlags = CERT_NAME_ISSUER_FLAG;
                              // Flag is set. Get the issuer's name
void *pvTypePara;             // Pointer to the a DWORD containing the
                              //   dwStrType, or Object Identifier
LPTSTR pszNameString;         // Pointer to the name string
DWORD cchNameString;          // # of characters converted-
                              //   including the terminating null
DWORD dwResult;               // Returns # of characters (including
                              //   the terminating NULL).

// Function call to CertGetNameString to get the required size
// of the destination string
dwResult= CertGetNameString(
            pCertContext,     // in
            CERT_NAME_EMAIL_TYPE,
                              // in - dwType
            CERT_NAME_ISSUER_FLAG,
                              // in - dwFlags to get the issuer's
                              //   name in lieu of the subject's name
            NULL,             // in - pvTypePara is set to NULL as
                              //   this is CERT_NAME_EMAIL_TYPE
            NULL,             // out, optional - pszNameString
                              //   set to NULL to get the required
                              //   size of the destination string
            0);               // in - cchNameString set to 0 to get
                              //   get the required size of the
                              //   destination string

cout<< "CertGetNameString returned a length of;"<< endl
    << "dwResult = "<< dwResult<< endl<< endl;

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Defined as Unicode and ANSI prototypes.


CertGetPublicKeyLength

The CertGetPublicKeyLength function gets the public/private key's bit length from the public key blob.

#include <wincrypt.h>
DWORD WINAPI CertGetPublicKeyLength(
  DWORD dwCertEncodingType,         // in
  PCERT_PUBLIC_KEY_INFO pPublicKey  // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pPublicKey
A pointer to the public key blob holding the keys for which the length is being retrieved.

Return Values

Returns the length of the public/private keys in bits. If unable to determine the key's length, returns zero.

Call GetLastError to see the reason for any failures.

Example

// EXAMPLE CODE FOR USING CertGetPublicKeyLength.
// Gets the public/private key's bit length from the public key blob.
// Assume that a pointer to the public key blob (pPublicKey is already
// defined.

// Set up the variables.
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                                  // Type of encoding
PCERT_PUBLIC_KEY_INFO pPublicKey; // Initialized elsewhere
DWORD dwResult;                   // Returns the length of
                                  //   public/private keys in bits

dwResult = CertGetPublicKeyLength(
            dwCertEncodingType,   // in
            pPublicKey);          // in

if (dwResult == 0) {
  cout<< "function unable to determine "<< endl
      << "key's length - 0 returned- "<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {
  cout<< "function succeeded"<< endl
      << "length = " << dwResult<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertIsRDNAttrsInCertificateName

The CertIsRDNAttrsInCertificateName function compares the attributes in the certificate name with the specified CERT_RDN to determine whether all attributes are included there. The comparison iterates through the CERT_RDN and looks for an attribute match in any of the certificate name's CERT_RDNs.

#include <wincrypt.h>
BOOL WINAPI CertIsRDNAttrsInCertificateName(
  DWORD dwCertEncodingType,    // in
  DWORD dwFlags,               // in
  PCERT_NAME_BLOB pCertName,   // in
  PCERT_RDN pRDN               // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

dwFlags
CERT_UNICODE_IS_RDN_ATTRS_FLAG must be set if the pRDN was initialized with UNICODE strings as in CryptEncodeObject(X509_UNICODE_NAME).
pCertName
A pointer to an encoded subject or issuer name.
pRDN
The array of attributes to be found in the name. The CERT_RDN_ATTR field of the CERT_RDN has the following special considerations.
CERT_RDN_ATTR | Comments
If pszObjId = NULL | Ignore the attribute Object Identifier.
If dwValueType = CERT_RDN_ANY_TYPE | Ignore the value type.
If Value.pbData = NULL | Match any value.

Return Values

Returns TRUE if all attributes are found and match. Returns FALSE if an error occurred.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_NO_MATCH | Not all the attributes were found and match.
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note: To get the OSS error, subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.

Remarks

Currently, only an exact, case-sensitive match is supported.

Example

// EXAMPLE CODE FOR USING CertIsRDNAttrsInCertificateName.
// Compares the attributes in the certificate name with the specified
// CERT_RDN to determine whether all attributes are included there.
// Assume that a pointer to the subject (pCertName) for which
// the intended attributes are being compared and a pointer to the
// array of attributes (pRDN) is already known

// Set up the variables.
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                             // Type of encoding
DWORD dwFlags = CERT_UNICODE_IS_RDN_ATTRS_FLAG;
                             // Initialized with UNICODE strings
PCERT_NAME_BLOB pCertName;   // Initialized elsewhere
PCERT_RDN pRDN;              // Initialized elsewhere
BOOL fResult;                // Returned TRUE if all attributes match
                             //   FALSE if an error occurs

fResult = CertIsRDNAttrsInCertificateName(
            dwCertEncodingType, // in - X509_ASN_ENCODING
            dwFlags,            // in - Flag set for X509 UNICODE_NAME
            pCertName,          // in - Pointer to subject
            pRDN);              // in - Pointer to array of attributes

if (!fResult) {                 // FALSE
  cout<< "function failed "<< endl
      << "not all attributes match "<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {                          // TRUE
  cout<< "all attributes match "<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertFindCertificateInStore


CertNameToStr

The CertNameToStr function converts a certificate name blob to a zero-terminated character string.

The string representation of distinguished names specified in RFC 1779 is adhered to. Deviations were made from RFC 1779 by double quoting embedded quotes, quoting empty strings, and not quoting strings containing consecutive spaces. RDN values of type CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING are formatted in hexadecimal (For example,#0A56CF).

#include <wincrypt.h>
DWORD WINAPI CertNameToStr(
  DWORD dwCertEncodingType,  // in
  PCERT_NAME_BLOB pName,     // in
  DWORD dwStrType,           // in
  LPTSTR pszNameString,      // out, optional
  DWORD cszNameString        // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pName
A pointer to the CERT_NAME_BLOB to be converted. See BLOB Structure.
dwStrType
Specifies the returned string type desired. The possible types are as follows.
CERT_SIMPLE_NAME_STR
The Object Identifiers are discarded. CERT_RDN entries are separated by ", ". Multiple attributes per CERT_RDN are separated by " + ". For example: Microsoft, Kim Abercrombie + Programmer.
CERT_OID_NAME_STR
The Object Identifiers are included with a "=" separator from their attribute value. CERT_RDN entries are separated by ", ". Multiple attributes per CERT_RDN are separated by "+ ". For example: 2.5.4.11=Microsoft, 2.5.4.3= Kim Abercrombie + 2.5.4.12=Programmer.
CERT_X500_NAME_STR
The Object Identifiers are converted to their X500 key name. Otherwise, same as CERT_OID_NAME_STR. If the Object Identifier doesn't have a corresponding X500 name, then, the Object Identifier is used with an "OID." prefix. For example: OU=Microsoft, CN=Kim Abercrombie + T=Programmer, OID.1.2.3.4.5.6=Unknown.

Quote the RDN value if it contains leading or trailing white space or one of the following characters: ",", "+", "=", """, "\n", "<", ">", "#" or ";". The quoting character is ". If the RDN Value contains a " it is double quoted (""). For example:

OU=" Microsoft", CN="Joe ""Cool""" + T="Programmer, Manager"

CERT_NAME_STR_SEMICOLON_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to replace the ", " separator with a "; " separator.
CERT_NAME_STR_CRLF_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to replace the ", " separator with a "\r\n" separator.
CERT_NAME_STR_NO_PLUS_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to replace the " + " separator with a single space, " ".
CERT_NAME_STR_NO_QUOTING_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to inhibit the above quoting.
CERT_NAME_STR_REVERSE-FLAG
This flag can be combined with a bitwise OR operation into dwStrType to specify that the order of the RDNs is to be reversed before converting to the string.

A reason for using this flag is that the names as they occur in the RDN are reversed from the typical manner in which they are displayed.

For example, an RDN in a certificate might look as follows:

Issuer::

[0,0] 2.5.4.7 (L) Internet

[1,0] 2.5.4.10 (O) VeriSign, Inc.

[2,0] 2.5.4.11 (OU) VeriSign Individual Software Publishers CA

It would be displayed as an X500 name string as follows:

<L=Internet, O="VeriSign, Inc.", OU=VeriSign Individual Software Publishers CA>

To interoperate with LDAP and the RFC standards, the displayed X500 name string should be reversed, by specifying CERT_NAME_STR_REVERSE-FLAG, and it would then be displayed as follows:

<OU=VeriSign Individual Software Publishers CA, O="VeriSign, Inc.", L=Internet>

CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to select the encoded value type. If this flag is set, and if all the UNICODE characters are <= 0xFF, the CERT_RDN_T61_STRING encoded value type is used instead of the CERT_RDN_UNICODE_STRING.
pszNameString
The address for the returned string.
cszNameString
The size, in characters, allocated for the returned string. The size must include the terminating NULL character.

Return Values

Returns the number of characters converted, including the terminating zero character. If pszNameString is NULL or cszNameString is zero, returns the required size of the destination string.

Remarks

If pszNameString is not NULL and cszNameString is not zero, the returned pszNameString is always zero terminated.

Example

See Certificate Management Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CertStrToName, CertRDNValueToStr


CertOIDToAlgId

The CertOIDToAlgId function converts the ASN.1 Object Identifier string to the CryptoAPI algorithm identifier (ALG_ID).

#include <wincrypt.h>
DWORD WINAPI CertOIDToAlgId(
  LPCSTR pszObjId     // in
);

Parameters

pszObjId
A pointer to the ASN.1 Object Identifier to be converted to an algorithm identifier.

Return Values

Returns zero if there isn't an algorithm identifier corresponding to the Object Identifier string.

Example

// EXAMPLE CODE FOR USING CertOIDToAlgId() to
// convert the szOID_RSA_RC4 Object Identifier string to an
// algorithm identifier.

// Set up the variables.
LPCSTR pszObjID = szOID_RSA_RC4;
DWORD Alg_Id;

Alg_Id = CertOIDToAlgId(pszObjID);

if (Alg_Id == 0)
   printf("No ALG_ID string correlates to the Object Identifier. \n");
else
   // Print the Alg_Id returned in hex.
   printf("%h", Alg_Id);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertRDNValueToStr

The CertRDNValueToStr function converts a Name Value to a zero-terminated character string.

#include <wincrypt.h>
DWORD WINAPI CertRDNValueToStr(
  DWORD dwValueType,            // in
  PCERT_RDN_VALUE_BLOB pValue,  // in
  LPTSTR pszValueString,        // out, optional
  DWORD cszValueString          // in
);

Parameters

dwValueType
The value type can be any one of the following:
CERT_RDN_ANY_TYPE
CERT_RDN_ENCODED_BLOB
CERT_RDN_OCTET_STRING
CERT_RDN_NUMERIC_STRING
CERT_RDN_PRINTABLE_STRING
CERT_RDN_TELETEX_STRING
CERT_RDN_T61_STRING
CERT_RDN_VIDEOTEX_STRING
CERT_RDN_IA5_STRING
CERT_RDN_GRAPHIC_STRING
CERT_RDN_VISIBLE_STRING
CERT_RDN_ISO646_STRING
CERT_RDN_GENERAL_STRING
CERT_RDN_UNIVERSAL_STRING
CERT_RDN_INT4_STRING
CERT_RDN_BMP_STRING
CERT_RDN_UNICODE_STRING

pValue
A pointer to an CERT_RDN_VALUE_BLOB that is of a type appropriate for the dwValueType. See BLOB Structure.
pszValueString
The address for the returned string.
cszValueString
The size, in characters, allocated for the returned string.

Return Values

Returns the number of characters converted, including the terminating zero character. If pszValueString is NULL or cszValueString is zero, returns the required size of the destination string.

Remarks

If pszValueString is not NULL and cszValueString is not zero, the returned pszValueString is always zero terminated.

Example

// EXAMPLE CODE FOR USING CertRDNValueToStr.
// Converts a Name Value to a zero-terminated character string.
// Assume that a pointer to the PCERT_RDN_VALUE_BLOB (pValue)
// for which the intended attributes are being compared is
// already known.

// Set up the variables.
DWORD dwValueType = CERT_RDN_ANY_TYPE;
                              // Value type
PCERT_RDN_VALUE_BLOB pValue;  // Initialized elsewhere
LPTSTR pszValueString;        // Address of returned string.
                              //   NULL returns the required size of
                              //   the string
DWORD cszValueString;         // Size, in characters, for the returned
                              //   string
DWORD dwResult;               // Returned value is # of characters
                              //   converted or required size

// Function called the first time to get
// the size of cszValueString
dwResult = CertRDNValueToStr(
             dwValueType,     // in - Any 1 of 17 value types
             pValue,          // in - Pointer for the
                              //    CERT_RDN_VALUE_BLOB
             NULL,            // NULL on the first call
             0);              // 0 on the first call

if (dwResult == 0) {          // Failure
  cout<< " first call to CertRDNValueToStr failed"<< endl;
}
else {
  cout<< " first call to CertRDNValueToStr successful"<< endl;
  pszValueString = (LPTSTR) malloc (cszValueString);
  cout<< "memory allocated"<< endl;
}

// Function call to convert name to string
dwResult = CertRDNValueToStr(
             dwValueType,     // in - Any 1 of 17 value types
             pValue,          // in - Pointer for the LPTSTR
             pszValueString,  // out- optional -
                              //   Address of string allocation
             cszValueString); // in - Size of the retuned string

cout<< "# of characters converted = "<< dwResult<< endl
  << "Converted String =" << pszValueString<< endl;
free (pValue);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CertNameToStr


CertRemoveEnhancedKeyUsageIdentifier

The CertRemoveEnhancedKeyUsageIdentifier function removes the usage identifier from the certificate's enhanced key usage property.

#include <wincrypt.h>
BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(
  PCCERT_CONTEXT pCertContext   // in
  LPCSTR pszUsageIdentifier     // in
);

Parameters

pCertContext
Specifies the certificate for which the usage identifier is to be removed.
pszUsageIdentifier
Specifies the usage identifier to remove.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

// EXAMPLE CODE FOR USING CertRemoveEnhancedKeyUsageIdentifier.
// Removes the usage identifier from the certificate's enhanced
// key usage property. Assume that a pointer to the certificate
// (pCertContext) for which the identifier is to be removed and
// a pointer to the identifier (pszUsageIdentifier) is already known.

// Set up the variables.
PCCERT_CONTEXT pCertContext;    // Initialized elsewhere
LPCSTR pszUsageIdentifier;      // Initialized elsewhere
BOOL fResult;                   // Returned TRUE if function succeeded
                                //   FALSE if function failed
fResult = CertRemoveEnhancedKeyUsageIdentifier(
            pCertContext,       // in - Pointer to the certificate
            pszUsageIdentifier);// in - Pointer to the usage
                                //   identifier

if (!fResult) {                 // FALSE
  cout<< "functional failed"<< endl
      << "error code = "<< GetLastError ()<< endl;
}
else {                          // TRUE
  cout<< "function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CertSetEnhancedKeyUsage

The CertSetEnhancedKeyUsage function sets the enhanced key usage property for the certificate.

#include <wincrypt.h>
BOOL WINAPI CertSetEnhancedKeyUsage(
  PCCERT_CONTEXT pCertContext,    // in
  PCERT_ENHKEY_USAGE pUsage       // in
);

Parameters

pCertContext
A pointer to the specified certificate.
pUsage
A pointer to the enhanced key usage information to set.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Example

// EXAMPLE CODE FOR USING CertSetEnhancedKeyUsage.
// Sets the enhanced key usage property for the certificate.
// Assume that a pointer to the certificate (pCertContext) and a
// pointer to the key usage information (pUsage) is already known.

// Set up the variables.
PCCERT_CONTEXT pCertContext; // Initialized elsewhere.
PCERT_ENHKEY_USAGE pUsage;   // Initialized elsewhere.
BOOL fResult;                // Returned TRUE if function successful.
                             //   False if function failed

fResult = CertSetEnhancedKeyUsage(
            pCertContext,    // in - Pointer to the certificate
            pUsage);         // in - Pointer to the key usage
                             //   identifier

if (!fResult) {              // FALSE
  cout<< "functional failed"<< endl
      << "error code = "<< GetLastError ()<< endl;
}
else {                       // TRUE
  cout<< "function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertGetEnhancedKeyUsage


CertStrToName

The CertStrToName function converts a NULL-terminated X500 string to an encoded certificate name. The input string is expected to be formatted the same as the output from CertNameToStr.

#include <wincrypt.h>
BOOL WINAPI CertStrToName(
  DWORD dwCertEncodingType,   // in
  LPCTSTR pszX500,            // in
  DWORD dwStrType,            // in
  void* pvReserved,           // in, optional
  BYTE* pbEncoded,            // out
  DWORD* pcbEncoded,          // in/out
  LPCTSTR* ppszError          // out, optional
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pszX500
A pointer to the zero-terminated X500 string to be converted.
dwStrType
The type of the input string. The possible types are as follows.

When dwStrType is set to 0, CERT_OID_NAME_STR or CERT_X500_NAME_STR, the input is allowed to contain either a case insensitive X500 key (CN=), case insensitive "OID." prefixed object identifier (OID.1.2.3.4.5.6=) or an object identifier (1.2.3.4=).

If no flags are combined with a bitwise OR operation into dwStrType, then, the input is allowed to contain "," or ";" as RDN separators and "+" as the multiple RDN value separator. Quoting is supported. A quote may be included in a quoted value by double quoting, for example (CN="Joe ""Cool"""). A value starting with a "#" is treated as ascii hex and converted to a CERT_RDN_OCTET_STRING. Embedded whitespace is skipped (1.2.3 = # AB CD 01 is the same as 1.2.3=#ABCD01).

Whitespace surrounding the keys, object identifiers and values are removed.

CERT_NAME_STR_COMMA_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to only allow the "," as the RDN separator.
CERT_NAME_STR_SEMICOLON_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to only allow the ";" as the RDN separator.
CERT_NAME_STR_CRLF_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to only allow "\r" or "\n" as the RDN separator.
CERT_NAME_STR_NO_PLUS_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to ignore "+" as a separator and not allow multiple values per RDN.
CERT_NAME_STR_NO_QUOTING_FLAG
This flag can be combined with a bitwise OR operation into dwStrType to inhibit quoting.
CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG
By default, CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as 8 bit characters. This flag can be combined with a bitwise OR operation into dwStrType to skip the initial attempt to decode as UTF8.
CERT_SIMPLE_NAME_STR
This type isn't supported since it doesn't contain any (CN=) type of information.
CERT_NAME_STR_REVERSE-FLAG
This flag can be combined with a bitwise OR operation into dwStrType to specify that the order of the RDNs is to be reversed after converting from the string and before encoding. See CertNameToStr for a demonstration of this flags usage.

The following X500 Keys are supported:
Key | Object Identifier | RDN Value Type(s)
CN | szOID_COMMON_NAME | Printable, T61
L | szOID_LOCALITY_NAME | Printable, T61
O | szOID_ORGANIZATION_NAME | Printable, T61
OU | szOID_ORGANIZATIONAL_UNIT_NAME | Printable, T61
Email | szOID_RSA_emailAddr | Only IA5
C | szOID_COUNTRY_NAME | Only Printable
S | szOID_STATE_OR_PROVINCE_NAME | Printable, T61
ST | szOID_STATE_OR_PROVINCE_NAME | Printable, T61
STREET | szOID_STREET_ADDRESS | Printable, T61
T | szOID_TITLE | Printable, T61
Title | szOID_TITLE | Printable, T61
G | szOID_GIVEN_NAME | Printable, T61
GivenName | szOID_GIVEN_NAME | Printable, T61
I | szOID_INITIALS | Printable, T61
Initials | szOID_INITIALS | Printable, T61
SN | szOID_SUR_NAME | Printable, T61
DC | szOID_DOMAIN_COMPONENT | Only IA5

If either Printable or T61 is allowed as the RDN Value Type for the key (CN=), then Printable is selected if the name string components are restricted to the following character set:

A, B, …, Z
a, b, …, z
0, 1, …, 9
(space) ' ( ) +, - . / : = ?

pvReserved
This parameter is reserved for future use and must be NULL.
pbEncoded
Pointer to a buffer that receives the encoded structure.

This parameter can be NULL to set the size of the key usage for memory allocation purposes. For more information, see the "Common In/Out Parameter Conventions" section at the beginning of this Reference.

pcbEncoded
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When the function returns, the variable pointed to by the pcbEncoded parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbEncoded is NULL.
ppszError
An application may specify a pointer for ppszError if designed to handle errors caused by invalid input strings.

If the input string is detected to be invalid, *ppszError is updated by this function to point to the beginning of the invalid character sequence. If no errors are detected in the input string, *ppszError is set to NULL.

ppszError can be set to NULL by the application if it is not interested in getting a pointer to the invalid character sequence, should one be found.

*ppszError is updated with a non-NULL pointer for the following errors:

CRYPT_E_INVALID_X500_STRING
CRYPT_E_INVALID_NUMERIC_STRING
CRYPT_E_INVALID_PRINTABLE_STRING
CRYPT_E_INVALID_IA5_STRING

Return Values

Returns TRUE if the input string was successfully parsed and the name was encoded without error. Otherwise, FALSE is returned.

Call GetLastError to see the reason for any failures.

Remarks

The T61 types are UTF-8 encoded.

Example

// EXAMPLE CODE FOR USING CertStrToName().
// Converts a X500 string to an encoded certificate name.
// Assume a pointer to the X500 string is already known.

// Set up the variables.
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                           // Type of encoding
LPCTSTR pszX500;           // Initialized elsewhere
DWORD dwStrType = 0;       // Type of input string
void * pvReserved = NULL;  // Reserved - set to NULL
BYTE * pbEncoded;          // Pointer to the BYTE blob
DWORD cbEncoded;           // # of bytes of the BYTE blob
LPCTSTR* ppszError;        // Error handling-out, optional
BOOL fResult;              // Returned TRUE if name is encoded
                           //   FALSE if error occurred

// Function called the first time to get
// the size of the structure
fResult = CertStrToName(
            dwCertEncodingType,
            pszX500,
            dwStrType,
            pvReserved,
            pbEncoded,
            &cbEncoded,
            ppszError);

if (!fResult){
 cout<< "First call to CertStrToName failed"<< endl;
}
else {
  cout<< "First call to CertStrToName successful"<< endl;
  pbEncoded = (BYTE*)malloc (cbEncoded);
  cout<< "memory allocated" << endl;
}

// Function call to convert string to name
fResult = CertStrToName(
            dwCertEncodingType,// in - Type of encoding
            pszX500,           // in - Pointer to the X500 string
            dwStrType,         // in - 0 allows case insensitive key
            pvReserved,        // in, optional - must be NULL
            pbEncoded,         // out - Pointer to the structure
            &cbEncoded,        // in/out - # of bytes in the structure
            ppszError);        // out, optional - Set to NULL- not
                               //   interested in getting a pointer to
                               //   the invalid character sequence

if (!fResult){                 // FALSE
  cout<< "String was not parsed "<< endl
      << "error code = "<< GetLastError ()<< endl;
}
else {                         // TRUE
  cout<< "String was parsed"<< endl
      << "encoded structure = "<< &pbEncoded<< endl
      << "of "<< cbEncoded<< " bytes"<< endl;
}
free (&pbEncoded);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.
Unicode: Defined as Unicode and ANSI prototypes.

See Also

CertNameToStr


CertVerifyCRLRevocation

The CertVerifyCRLRevocation function verifies that the subject certificate is not on the CRL.

#include <wincrypt.h>
BOOL WINAPI CertVerifyCRLRevocation(
  DWORD dwCertEncodingType,  // in
  PCERT_INFO pCertId,        // in
  DWORD cCrlInfo,            // in
  PCRL_INFO rgpCrlInfo       // in
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pCertId
A pointer to the subject certificate that is being checked against the CRL.
cCrlInfo
The number of CRL_INFO pointers in the rgpCrlInfo array.
rgpCrlInfo
An array of CRL_INFO pointers.

Return Values

Returns TRUE if the certificate is not on the CRL.

Example

// EXAMPLE CODE FOR USING CertVerifyCRLRevocation() to
// verify whether a subject certificate is on a CRL.

// Assume that a pointer to the certificate (pCertId) for which the
// revocation verification is to be performed is already known, that
// the type of encoding used on the certificate is X509_ASN_ENCODING,
// and that the array of CRL_INFO pointers has already been
// constructed (in rgpCrlInfo) and that it has 5 elements.

// Set up the variables.
PCERT_INFO pCertId;          // Initialized elsewhere
PCRL_INFO rgpCrlInfo[5];     // Initialized elsewhere
BOOL Return;

Return = CertVerifyCRLRevocation(
            X509_ASN_ENCODING, pCertId, 5, rgpCrlInfo);

if (Return == TRUE) {
    // The certificate is not on the CRL. Continue as desired.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertVerifyCRLTimeValidity, CertVerifyTimeValidity, CertVerifyValidityNesting


CertVerifyCRLTimeValidity

The CertVerifyCRLTimeValidity function verifies the time validity of a CRL.

#include <wincrypt.h>
LONG WINAPI CertVerifyCRLTimeValidity(
  LPFILETIME pTimeToVerify,    // in
  PCRL_INFO pCRLInfo           // in
);

Parameters

pTimeToVerify
A pointer to the time to be verified. If set to NULL, the current time is used.
pCRLInfo
A pointer to the CRL for which the time is being verified.

Return Values

Returns a minus one if the time being verified is before "ThisUpdate". Returns a plus one if the time being verified is after "NextUpdate". Returns zero for valid time for the CRL.

Example

// EXAMPLE CODE FOR USING CertVerifyCRLTimeValidity().
// Verifies the time validity of a CRL. Assume that a pointer to
// the CRL (PCRL_INFO) is already known.
// In this example, the current time is used.

// Set up the variables.
LPFILETIME pTimeToVerify = NULL;// Pointer to the time to be verified
PCRL_INFO pCRLInfo;             // Initialized elsewhere
long lResult;                   // Returned value
                                //    -1 is before ThisUpdate
                                //    0 for a valid time for the CRL
                                //    +1 if after NextUpdate

lResult= CertVerifyCRLTimeValidity(
           pTimeToVerify,       // in - NULL means current time
           pCRLInfo);           // in - Pointer to the CRL

if (lResult == -1){             // time is before "ThisUpdate"
  cout<< "time is before ThisUpdate"<< endl;
}
else if (lResult == 0){         // time is valid
  cout<< "time is valid"<< endl;
}
else if (lResult == 1){         // time is after "NextUpdate"
  cout<< "time is after NextUpdate"<< endl;
}
else {                          // return value is invalid
  cout<< "You should not be here"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertVerifyCRLRevocation, CertVerifyTimeValidity, CertVerifyValidityNesting


CertVerifyCTLUsage

The CertVerifyCTLUsage function verifies that a subject is trusted for a specified usage by finding a signed and time valid CTL with the usage identifiers that contains the subject. A subject can be identified by either its certificate context or any identifier such as its SHA1 hash.

#include <wincrypt.h>
BOOL WINAPI CertVerifyCTLUsage(
  DWORD dwEncodingType,                        // in
  DWORD dwSubjectType,                         // in
  void* pvSubject,                             // in
  PCTL_USAGE pSubjectUsage,                    // in
  DWORD dwFlags,                               // in
  PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,     // in, optional
  PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus  // in/out
);

Parameters

dwEncodingType
The type of encoding used. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwSubjectType
See dwSubjectType in CertFindSubjectInCTL for definition.
pvSubject
See pvSubject in CertFindSubjectInCTL for definition.
pSubjectUsage
A pointer to a CTL_USAGE structure. It is used to specify the intended usage of the subject.
dwFlags
If the CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG isn't set, then a time invalid CTL in one of the stores specified by rghCtlStore in CTL_VERIFY_USAGE_PARA may be replaced. When replaced, the CERT_VERIFY_UPDATED_CTL_FLAG is set in pVerifyUsageStatus->dwFlags. If this flag is set, then even if a time valid updated CTL is received for a CTL that is currently time invalid in the store, an update will not be made.

If the CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, then, only the signer stores specified by rghSignerStore in CTL_VERIFY_USAGE_PARA are searched to find the signer. Otherwise, the signer stores provide additional sources to find the signer's certificate. See the Remarks for further details.

If CERT_VERIFY_NO_TIME_CHECK_FLAG is set, then, the CTLs aren't checked for time validity. Otherwise, they are.

If CERT_VERIFY_ALLOW_MORE_USAGE_FLAG is set, then, the CTL may contain additional usage identifiers than specified by pSubjectUsage. Otherwise, the found CTL will contain the same usage identifiers and no additional ones.

pVerifyUsagePara
With pVerifyUsagePara, the caller can specify the stores to be searched to find the CTL. The caller can also specify the stores containing acceptable CTL signers. By setting the ListIdentifier, the caller can also be limited to a particular signer CTL list.
pVerifyUsageStatus
Only the cbSize member of the CTL_VERIFY_USAGE_STATUS needs to be set for this parameter when CertVerifyCTLUsage is called. However, all unused fields must be zeroed. See CTL_VERIFY_USAGE_STATUS for additional details.

Return Values

If the subject is trusted for the specified usage, then, TRUE is returned. Otherwise, FALSE is returned with dwError set to one of the following:

CRYPT_E_NO_VERIFY_USAGE_DLL

CRYPT_E_NO_VERIFY_USAGE_CHECK

CRYPT_E_VERIFY_USAGE_OFFLINE

CRYPT_E_NOT_IN_CTL

CRYPT_E_NO_TRUSTED_SIGNER

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_NO_VERIFY_ USAGE_DLL | No Dll or exported function was found to verify subject usage.
CRYPT_E_NO_VERIFY_ USAGE_CHECK | The called function wasn't able to do a usage check on the subject.
CRYPT_E_VERIFY_ USAGE_OFFLINE | Since the server was offline, the called function wasn't able to complete the usage check.
CRYPT_E_NOT_IN_CTL | The subject wasn't found in a Certificate Trust List (CTL).
CRYPT_E_NO_TRUSTED_ SIGNER | No trusted signer was found to verify the signature of the message or trust list.

Remarks

CertVerifyCTLUsage will be implemented as a dispatcher to OID installable functions. First, it will try to find an OID function matching the first usage object identifier in the pSubjectUsage sequence. Next, it will dispatch to the default CertDllVerifyCTLUsage functions.

Microsoft has implemented an OID installable CertDllVerifyCTLUsage function residing in the cryptnet.dll with the following properties:

  • If CTL stores are specified by rghCtlStore in pVerifyUsagePara, then, only those stores are searched to find a CTL. Otherwise, the "Trust" system store is searched to find a CTL.
  • If CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, then, only the signer stores specified by rghSignerStore in pVerifyUsagePara are searched to find the certificate corresponding to the signer's issuer and serial number. Otherwise, the CTL message's store, signer stores specified by rghSignerStore in pVerifyUsagePara, "Trust" system store, "CA" system store, "ROOT" and "SPC" system stores are searched to find the signer's certificate. In either case, the public key in the found certificate is used to verify the CTL's signature.
  • If the CTL has a NextUpdate and CERT_VERIFY_NO_TIME_CHECK isn't set, then it's verified for time validity.
  • If the CTL obtained from the store is time invalid, then, an attempt is made to get a time valid version. Uses either the CTL's NextUpdateLocation property or CTL's NextUpdateLocation extension or searches the signer's information for a NextUpdateLocation attribute.

Example

// EXAMPLE CODE FOR USING CertVerifyCTLUsage().
// Verifies that a subject is trusted.
// Assume that the application has pointers to
// CERT_CONTEXT (pvSubject), PCTL_USAGE (pSubjectUsage),
// PCTL_VERIFY_USAGE_PARA (pVerifyUsagePara), and
// PCTL_VERIFY_USAGE_STATUS (pVerifyUsageStatus).

// Set up the variables.
DWORD dwEncodingType = X509_ASN_ENCODING;
                         // Type of encoding
DWORD dwSubjectType = CTL_CERT_SUBJECT_TYPE;
                         // CERT_CONTEXT or CTL_ANY_SUBJECT_INFO
CERT_CONTEXT* pvSubject; // Initialized elsewhere
PCTL_USAGE pSubjectUsage;// Initialized elsewhere
DWORD dwFlags = 0;       // The flag values
PCTL_VERIFY_USAGE_PARA pVerifyUsagePara;
                         // Initialized elsewhere
PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus;
                         // Initialized elsewhere
BOOL fResult;            // Return True if subject is trusted
                         //   FALSE otherwise
fResult= CertVerifyCTLUsage(
           dwEncodingType,     // in - CRYPT_ASN_ENCODING
           dwSubjectType,      // in
           pvSubject,          // in
           pSubjectUsage,      // in - Specify the store to be
                               //   searched
           dwFlags,            // in - Set to 0
           pVerifyUsagePara,   // in - optional
           pVerifyUsageStatus);// in/out

if (!fResult) {                // FALSE
 cout<< "Subject is not trusted"<< endl
     << "dwError = "<< pVerifyUsageStatus->dwError<< endl
     << "error code = "<< GetLastError ()<< endl;
}
else {                         // TRUE
 cout<< "Subject is trusted"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CTL_VERIFY_USAGE_PARA,
CTL_VERIFY_USAGE_STATUS,
CertFindSubjectInCTL,
CertFindCTLInStore


CertVerifyRevocation

The CertVerifyRevocation function verifies that a list of certificates (contained in the rgpvContext[] array) have not been revoked. Once a certificate in the list has been found to be revoked, no further checking is done. This list may be a chain of certificates propagating upwards from an end entity to the root CA. However, it is not required or assumed that the list is a chain of related certificates.

#include <wincrypt.h>
BOOL WINAPI CertVerifyRevocation(
  DWORD dwCertEncodingType,           // in
  DWORD dwRevType,                    // in
  DWORD cContext,                     // in
  PVOID rgpvContext[],                // in
  DWORD dwFlags,                      // in
  PCERT_REVOCATION_PARA pRevPara,     // in/optional
  PCERT_REVOCATION_STATUS pRevStatus  // in/out
);

Parameters

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

dwRevType
Indicates the type of the context data structure passed in rgpvContext[]. Currently only the revocation of certificates is defined. The revocation type that corresponds to the revocation of certificates is shown in the following table:
Revocation type | Value
CERT_CONTEXT_REVOCATION_TYPE | 0x00000001

cContext
The count of elements in the rgpvContext array.
rgpvContext[]
When the dwRevType is CERT_CONTEXT_REVOCATION_TYPE, then rgpvContext[] is an array of PCERT_CONTEXT (pointers to CERT_CONTEXT) elements. These contexts must contain sufficient information to allow the installable or registered revocation DLLs to find the revocation server. This information would normally be conveyed in an extension such as the Internet Explorer Task Force (IETF) AuthorityInfoAccess extension.

For efficiency, the more contexts that are passed in at one time, the better.

dwFlags
The flag values. If the CERT_VERIFY_REV_CHAIN_FLAG flag is set, then CertVerifyRevocation is verifying a chain of certificates where, rgpvContext[i + 1] is the issuer of rgpvContext[i]. Otherwise, CertVerifyRevocation makes no assumptions about the order of the contexts.
pRevPara
To assist in finding the issuer, the pRevPara may optionally be set. See the CERT_REVOCATION_PARA data structure for details
pRevStatus
Only the cbSize member of the CERT_REVOCATION_STATUS needs to be set for this parameter when CertVerifyRevocation is called. See CERT_REVOCATION_STATUS for additional details.

If FALSE is returned from CertVerifyRevocation, this structure's members will contain error status. See CERT_REVOCATION_STATUS for additional detail. See the "Remarks" section below for an example describing how pRevStatus is updated when a revocation verification problem is encountered.

Return Values

CertVerifyRevocation returns TRUE if all of the contexts were successfully checked and none were revoked. Otherwise, it returns FALSE and updates the returned pRevStatus data structure as described in CERT_REVOCATION_STATUS.

When the revocation handler for any of the contexts returns FALSE due to an error, the dwError member in pRevStatus will be set by the handler to specify which error was encountered. CertVerifyRevocation will then set LastError equal to the error specified in dwError. For more information, see Handler Return Value Requirements.

For a return value of FALSE, pRevStatus -> dwError should be examined or GetLastError should be called to determine the exact reason for failure.

Error code | Description
CRYPT_E_NO_REVOCATION_CHECK | An installed or registered revocation function wasn't able to do a revocation check on the context.
CRYPT_E_NO_REVOCATION_DLL | No installed or registered Dll was found that was able to verify revocation.
CRYPT_E_NOT_IN_REVOCATION_DATABASE | The context to be checked was not found in the revocation server's database.
CRYPT_E_REVOCATION_OFFLINE | It was not possible to connect to the revocation server.
CRYPT_E_REVOKED | The context was revoked. dwReason in pRevStatus contains the reason for revocation.
ERROR_SUCCESS | The context was good.
E_INVALIDARG | cbSize in pRevStatus is less than sizeof(CERT_REVOCATION_STATUS). Note that dwError in pRevStatus is not updated for this error.

Remarks

The following example shows how pRevStatus is updated when a revocation verification problem is encountered:

Consider the case where cContext = 4. If CertVerifyRevocation was able to verify that rgpvContext[0] and rgpvContext[1] were not revoked, but it was not able to check rgpvContext[2], then the pRevStatus member dwIndex is set equal to 2, indicating that the context at index two had the problem, pRevStatus member dwError is set equal to CRYPT_E_NO_REVOCATION_CHECK, and FALSE is returned. If rgpvContext[2] was determined to be revoked, then pRevStatus member dwIndex is set equal to 2, pRevStatus member dwError is set equal to CRYPT_E_REVOKED, dwReason would be updated, and FALSE is returned. In either case, both rgpvContext[0] and rgpvContext[1] were verified not to be revoked, rgpvContext[2] was the last array index checked, and rgpvContext[3] wasn't checked at all.

For information about extending the CertVerifyRevocation functionality by using installable revocation handlers, see Extending CertVerifyRevocation Functionality.

Example

// EXAMPLE CODE FOR USING CertVerifyRevocation().
// This function verifies that a list of certificates
// have not been revoked.
// Assume that the application has a pointer to both
// the PCERT_REVOCATION_PARA (pRevPara) and
// PCERT_REVOCATION_STATUS (pRevStatus).

// Set up the variables.
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                       // Type of encoding
DWORD dwRevType = CERT_CONTEXT_REVOCATION_TYPE;
                       // Type of context data
DWORD cContext =128;   // # of elements in rgpvContext
PVOID rgpvContext[128];// Array of pointers to CERT_CONTEXT
                       //   elements. These elements must contain
                       //   information to find the revocation server.
DWORD dwFlags = NULL;  // flag values
PCERT_REVOCATION_PARA pRevPara;
                       // Initialized elsewhere
PCERT_REVOCATION_STATUS pRevStatus;
                       // Initialized elsewhere
BOOL fResult;          // Return TRUE if all contexts are OK
                       //   FALSE if any context revoked

pRevStatus->cbSize= sizeof(CERT_REVOCATION_STATUS);
                       // cbSize member of CERT_REVOCATION_STATUS
                       //   needs to be set
fResult= CertVerifyRevocation(
           dwCertEncodingType,    // in - X509_ASN_ENCODING
           dwRevType,         // in - CERT_CONTEXT-REVOCATION-TYPE
           cContext,          // in - # of elements in the rgpvContext
                              //   array
           rgpvContext,       // in - array of pointers
           dwFlags,           // in - Flag Values
           pRevPara,          // in/optional
           pRevStatus);       // in/out

fResult= FALSE;
if (!fResult) {               // FALSE
  cout<< "Certificate revoked"<< endl
     << "revokation status = "<< pRevStatus->dwError<< endl;
}
else {                        // TRUE
  cout<< "No certificates revoked"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertVerifyCRLTimeValidity, CertVerifyTimeValidity, CertVerifyValidityNesting


CertVerifyTimeValidity

The CertVerifyTimeValidity function verifies the time validity of a certificate.

#include <wincrypt.h>
LONG WINAPI CertVerifyTimeValidity(
  LPFILETIME pTimeToVerify,     // in
  PCERT_INFO pCertInfo          // in
);

Parameters

pTimeToVerify
A pointer to the time to be verified. If set to NULL the current time is used.
pCertInfo
A pointer to the certificate for which the time is being verified.

Return Values

Returns a minus one if the time being verified is before "NotBefore". Returns a plus one if the time being verified is after "NotAfter". Returns zero for valid time for the certificate.

Example

See Certificate Management Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertVerifyCRLTimeValidity, CertVerifyCRLRevocation, CertVerifyValidityNesting


CertVerifyValidityNesting

The CertVerifyValidityNesting function verifies that the subject's time validity nests within the issuer's time validity.

#include <wincrypt.h>
BOOL WINAPI CertVerifyValidityNesting(
  PCERT_INFO pSubjectInfo,     // in
  PCERT_INFO pIssuerInfo       // in
);

Parameters

pSubjectInfo
A pointer to the subject certificate.
pIssuerInfo
A pointer to the issuer certificate.

Return Values

Returns TRUE if it nests. Otherwise, returns FALSE.

Example

// EXAMPLE CODE FOR USING CertVerifyValidityNesting() to
// verify that a subject's time validity nests within an issuer's time validity

// Assume that that pointers to the subject (pSubjectInfo) and
// issuer (pIssuerInfo) that are being checked for time validity
// nesting are already known.

// Set up the variables.
PCERT_INFO pSubjectInfo, pIssuerInfo;  // Initialized elsewhere
BOOL Return;

Return = CertVerifyValidityNesting(
            pSubjectInfo, pIssuerInfo);

if (Return == TRUE) {
    // The subject's time validity nests within the
    // issuer's time validity. Continue as desired.
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CertVerifyCRLTimeValidity, CertVerifyCRLRevocation, CertVerifyTimeValidity


CryptAcquireCertificatePrivateKey

[This is preliminary documentation and subject to change.]

The CryptAcquireCertificatePrivateKey function acquires a HCRYPTPROV handle and dwKeySpec for the specified certificate context.

#include <wincrypt.h>
BOOL WINAPI CryptAcquireCertificatePrivateKey(
  PCCERT_CONTEXT pCert,        // in
  DWORD dwFlags,               // in
  void *pvReserved,            // in
  HCRYPTPROV *phCryptProv,     // out
  DWORD *pdwKeySpec,           // out, optional
  BOOL *pfCallerFreeProv       // out, optional
);

Parameters

pCert
Pointer to the specified certificate context. This is the certificate context for which a private key will be acquired.
dwFlags
The following flags are defined;
Flag name value Description
CRYPT_ACQUIRE_

CACHE_FLAG

 0x1 A HCRYPTPROV is returned as a phCryptProv. If a HCRYPTPROV is already acquired and cached, that HCRYPTPROV is returned. Otherwise a new HCRYPTROV is acquired and cached via the certificate's CERT_KEY_CONTEXT_PROP_ID.

In any case, when this flag is set, *pfCallerFreeProv is returned FALSE and the caller must not free the cached HCRYPTPROV

CRYPT_ACQUIRE_

USE_PROV_INFO_FLAG

 0x2 Uses the certificate's property CERT_KEY_PROV_INFO_PROP_ID (see CertSetCertificateContextProperty) to determine if caching should be accomplished.

Uses caching, only if during a previous call to CRYPT_KEY_PROV_INFO, the dwFlags was set to CERT_SET_KEY_CONTEXT_PROP.

CRYPT_ACQUIRE_

COMPARE_KEY_FLAG

0x4 The public key in the certificate is compared with the public key returned by the cryptographic service provider. If the keys do not match, the acquire fails and LastError is set to NTE_BAD_PUBLIC_KEY. If a cached HCRYPTPROV is returned, no comparison is made.

pvReserved
This parameter is reserved for future use and must be NULL.
phCryptProv
Pointer to the returned HCRYPTPROV. Depending on the dwFlags, HCRYPTPROV must be freed by the caller or explicitly freed on the last free action of the certificate context.
pdwKeySpec
Pointer to the specification of the private key.

The following dwKeySpec values are defined in Wincrypt.h for the default provider:
AT_KEYEXCHANGE | 1
AT_SIGNATURE | 2

pfCallerFreeProv
Pointer to a flag. The flag is returned set to FALSE if:

Acquire or public key comparison fails.

CRYPT_ACQUIRE_CACHE_FLAG is set.

CRYPT_ACQUIRE_USE_PROV_INFO_FLAG is set AND the certificate context property is set to CERT_KEY_PROV_INFO_PROP_ID with the CRYPT_KEY_PROV_INFO data structure, dwFlags paramater set to CERT_SET_KEY_CONTEXT_PROP_ID.

When the fCallerFreeProv flag is returned FALSE, the caller must not release the returned HCRYPTPROV. The returned HCRYPTPROV will be released on the last free action of the certificate context.

When the fCallerFreeProv flag is set TRUE, the returned HCRYPTPROV must be released by calling CryptReleaseContext.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Error code | Description
NTE_BAD_PUBLIC_KEY | The public key in the certificate does not match the public key returned by the cryptographic provider. This error code is available if the CRYPT_ACQUIRE_COMPARE_KEY_FLAG is set and the public key in the certificate does not match the public key returned by the cryptographic provider.

Example

// EXAMPLE CODE FOR USING CryptAcquireCertificatePrivateKey().
// Assume that a pointer to the certificate (pCert) is already known.
// Set up the variables.
PCCERT_CONTEXT pCert;         // Pointer to the specified certificate
                              //   Initialized elsewhere
DWORD dwFlags = CRYPT_ACQUIRE_CACHE_FLAG;
                              // Flag is set. Search for a cached
                              //   HCRYPTPROV. If none is found,
                              //   acquire, and cache a HCRYPTPROV
void *pvReserved = NULL;      // This parameter is reserved for future
                              //   use and must be NULL.
HCRYPTPROV *phCryptProv;      // Pointer to the cached HCRYPTPROV
DWORD *pdwKeySpec;            // Pointer to the specification
                              //   of the private key
BOOL *pfCallerFreeProv;       // if *pfCallerFreeProv is returned
                              //   false do not release HCRYPTPROV.
BOOL fResult;                 // Return TRUE if the function succeeded
                              //   FALSE if the function failed

// Function call to CryptAcquireCertificatePrivateKey
// to get the handle of the matching HCRYPTPROV.
fResult= CryptAcquireCertificatePrivateKey(
           pCert,            // in - the HCRYPTPROV to be searched-
                             //   acquired elsewhere
           CRYPT_ACQUIRE_CACHE_FLAG,
                             // in - dwFlags set to search and locate
                             //   an already acquired and cached
                             //   certificate or to acquire and
                             //   cache a certificate
           NULL,             // in - pvReserved is set to NULL
           phCryptProv,      // out - phCryptProv is the pointer
                             //   to the cached HCRYPTPROV
           pdwKeySpec,       // out, optional - pdwKeySpec is a
                             //   pointer to dwKeySpec for the
                             //   specified certificate
           pfCallerFreeProv);// out, optional

cout<< "CryptAcquireCertificatePrivateKey;"<< endl
    << "fResult = "<< fResult<< endl<< endl;
if (fResult) {               // returned value is TRUE
                             //   an acquire is successful
    cout<< "the HCRYPTPROV at "<< phCryptProv<< "is cached"<< endl
        << "the dwKeySpec is "<< &pdwKeySpec<< endl<< endl;
    if (*pfCallerFreeProv) { // TRUE- release HCRYPTPROV
        cout<< "release HCRYPTPROV"<< endl << endl;
        CryptReleaseContext( // call & release HCRYPTPROV.
        *phCryptProv,
        0);                  // set dwFlags to 0
     }
     else {                  // FALSE- do not release HCRYPTPROV
        cout<< "do not release HCRYPTPROV"<< endl << endl;
     }
}
else {                       // returned value is FALSE
     cout<< "acquire failed" << endl << endl;
}
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptExportPublicKeyInfo

The CryptExportPublicKeyInfo function exports the public key information associated with the provider's corresponding private key.

#include <wincrypt.h>
BOOL WINAPI CryptExportPublicKeyInfo(
  HCRYPTPROV hCryptProv,        // in
  DWORD dwKeySpec,              // in
  DWORD dwCertEncodingType,     // in
  PCERT_PUBLIC_KEY_INFO pInfo,  // out
  DWORD *pcbInfo                // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use when exporting the public key information.
dwKeySpec
Identifies the public key to use from the provider's container. For example, AT_KEYEXCHANGE or AT_SIGNATURE.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pInfo
Pointer to a buffer that receives the public key information to be exported.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbInfo
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pInfo parameter. When the function returns, the variable pointed to by the pcbInfo parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pInfo is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptGetUserKey and CryptExportKey may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Public key ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_MORE_DATA | If the buffer specified by the pInfo parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbInfo.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.

Example

See Certificate Request Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptImportPublicKeyInfo


CryptExportPublicKeyInfoEx

The CryptExportPublicKeyInfoEx function exports the public key information associated with the provider's corresponding private key. The main difference from CryptExportPublicKeyInfo is that the user can specify the public key algorithm, overriding the default provided by the CSP.

#include <wincrypt.h>
BOOL WINAPI CryptExportPublicKeyInfoEx(
  HCRYPTPROV hCryptProv,         // in
  DWORD dwKeySpec,               // in
  DWORD dwCertEncodingType,      // in
  LPSTR pszPublicKeyObjId,       // in
  DWORD dwFlags,                 // in
  void *pvAuxInfo,               // in, optional
  PCERT_PUBLIC_KEY_INFO pInfo,   // out
  DWORD *pcbInfo                 // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use when exporting the public key information.
dwKeySpec
Identifies the public key to use from the provider's container. For example, AT_KEYEXCHANGE or AT_SIGNATURE.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pszPublicKeyObjId
Specifies the public key algorithm. Note that pszPublicKeyObjId and dwCertEncodingType are used together in determining the installable CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC to call. If an installable function was not found for the pszPublicKeyObjId, an attempt is made to export the key as a RSA Public Key (szOID_RSA_RSA).
dwFlags
The flag values. This parameter is reserved for future use and should be set to zero in the interim.
pvAuxInfo
This parameter is reserved for future use and should be set to NULL in the interim.
pInfo
Ppointer to a buffer that receives the public key information to be exported.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbInfo
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pInfo parameter. When the function returns, the variable pointed to by the pcbInfo parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pInfo is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptGetUserKey and CryptExportKey may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Public key ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | An installable or registerable export function could not be found for the specified dwCertEncodingType and pszPublicKeyObjId.
ERROR_MORE_DATA | If the buffer specified by the pInfo parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbInfo.

Example

// EXAMPLE CODE FOR USING CryptExportPublicKeyInfoEx().
// Exports the public key information associated with the provider's
// corresponding private key.
// Assume that a pointer to the public key information
// PCERT_PUBLIC_KEY_INFO is already known.

// Set up the variables.
HCRYPTPROV hCryptProv = NULL;     // Service Provider handle
DWORD dwKeySpec = AT_KEYEXCHANGE; // Public key spec
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                                  // Type of encoding
LPSTR pszPublicKeyObjId = szOID_RSA_RC4;
                                  // Public key algorithm
DWORD dwFlags = 0;                // Future use- set to 0
void * pvAuxInfo = NULL;          // Future use- set to NULL
PCERT_PUBLIC_KEY_INFO pInfo;      // Initialized elsewhere
DWORD cbInfo;                     // DWORD for size
BOOL fResult;                     // Return TRUE if function succeeded
                                  //   false if function failed

// Function called the first time to get
// the size of pcbInfo - allocated memory
fResult= CryptExportPublicKeyInfoEx(
           hCryptProv,
           dwKeySpec,
           dwCertEncodingType,
           pszPublicKeyObjId,
           dwFlags,
           pvAuxInfo,
           NULL,              // NULL on first call
           &cbInfo);          // Address for the byte count
if (!fResult) {               // FALSE
  cout<< "first call CryptExportPublicKeyInfoEx failed"<< endl;
}
else {                        // TRUE
  cout<< "first call CryptExportPublicKeyInfoEx successful"<< endl;
  pInfo = (PCERT_PUBLIC_KEY_INFO)malloc(cbInfo);
  cout<< "memory allocated"<< endl;
}

// Call to CryptExportPublicKeyInfoEx to get the public key
// information.
fResult= CryptExportPublicKeyInfoEx(
           hCryptProv,        // in - 0 = the default RSA or DSS
                              //   provider
           dwKeySpec,         // in - CERT_CONTEXT-REVOCATION-TYPE
           dwCertEncodingType,// in - X509_ASN_ENCODING
           pszPublicKeyObjId, // in - Public key algorithm
           dwFlags,           // in - set to 0
           pvAuxInfo,         // in - set to NULL
           pInfo,             // out- Pointer to returned public key
                              //   information
           &cbInfo);          // in/out - Size of the public key
                              //   information

if (!fResult) {               // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                        // TRUE
 cout<< "Function succeeded"<< endl;
}
free (pInfo);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptImportPublicKeyInfoEx


CryptFindCertificateKeyProvInfo

[This is preliminary documentation and subject to change.]

The CryptFindCertificateKeyProvInfo function enumerates the cryptographic providers and their containers to find the private key corresponding to the certificate's public key.

#include <wincrypt.h>
BOOL WINAPI CryptFindCertificateKeyProvInfo(
  PCCERT_CONTEXT pCert,        // in
  DWORD dwFlags,               // in
  void *pvReserved             // in
);

Parameters

pCert
Specifies the certificate to use when exporting public key information.
dwFlags
The flag values.
Flag name Value Description
CRYPT_FIND_USER_

KEYSET_FLAG

 0x1 Restricts the search to the user container.
CRYPT_FIND_MACHINE_

KEYSET_FLAG

0x2 Restricts the search to the machine container.

If no flag value is specified, both the user and the machine containers are searched.

pvReserved
This parameter is reserved for future use and must be NULL.

Note This function enumerates the cryptographic provider and its containers to find the private key corresponding to the certificate's public key. For a match, the function updates the certificate's CERT_KEY_PROV_INFO_PROP_ID property. If the CERT_KEY_PROV_INFO_PROP_ID is already set, then it is checked to see if it matches the provider's public key. For a match, the function skips the previously mentioned enumeration.

Return Values

TRUE if the function finds a private key corresponding to the certificate's public key within a searched container, FALSE if the function fails to find a container or a private key within a container.

Call GetLastError to see the reason for any failures.

Error code | Description
NTE_NO_KEY | No container found.

Example

// EXAMPLE CODE FOR USING CryptFindCertificateKeyProvInfo().
// Assume that a pointer (pCert) to a certificate has
// already been defined.
// Set up the variables.
PCCERT_CONTEXT pCert;    // Pointer to certificate
DWORD dwFlags;           // Flags value
DWORD *pvReserved;       // Pointer - reserved, set to NULL
BOOL fResult;            // Return TRUE if a private key
                         //   corresponds to a public key
                         //   FALSE if not found

// Function call to CryptFindCertificateKeyProvInfo.
fResult= CryptFindCertificateKeyProvInfo(
       pCert,            // in - A pointer to a certificate
                         //    defined elsewhere
       CRYPT_FIND_MACHINE_KEYSET_FLAG,
                         // in - search only machine key
                         //   containers
       NULL);            // in - Reserved paramater, set to
                         //   NULL

cout<< "CryptFindCertificateKeyProvInfo;"<< endl
    << "fResult = "<< fResult<< endl<< endl;
if (fResult) {           // TRUE- a corresponding set of
                         //   keys found
  cout<< "private key corresponding to the"<< endl
      << "certificate's public key has been located "
      << endl<< endl;
}
else {                   // FALSE- no corresponding set of keys found
  cout<< "no private key corresponding to the"<< endl
      << "certificate's public key has been located "<< endl
      << "error = "<< GetLastError()<< endl;
                         // LastError should be set to
                         //   NTE_NO_KEY
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptFindLocalizedName

[This is preliminary documentation and subject to change.]

The CryptFindLocalizedName function finds the localized name for the specified name, such as the "Root" system store name.

#include <wincrypt.h>
LPCWSTR WINAPI CryptFindLocalizedName(
  LPCWSTR pwszCryptName        // in
);

Parameters

pwszCryptName
A pointer to a specified name. An internal table is searched to compare a predefined localized name to the specified name. The search matches the localized name using a case insensitive string comparison.

Note Localized names for the predefined system stores ("Root", "My") and predefined physical stores (".Default", ".LocalMachine") are pre-installed as resource strings in crypt32.dll.

Return Values

If the specified name is found, a pointer to the localized name is returned. The returned pointer MUST NOT be freed.

If the specified name is not found, a NULL is returned.

Remarks

CryptSetOIDFunctionValue can be called as follows to register additional localized strings:

dwEncodingType = CRYPT_LOCALIZED_NAME_ENCODING_TYPE

pszFuncName = CRYPT_OID_FIND_LOCALIZED_NAME_FUNC

pszOID = CRYPT_LOCALIZED_NAME_OID

pwszValueName = Name to be localized, for example, L"ApplicationStore"

dwValueType = REG_SZ

pbValueData = pointer to the UNICODE localized string

cbValueData = (wcslen(UNICODE localized string) + 1) * sizeof(WCHAR)

CryptSetOIDFunctionValue can be called as follows to unregister the localized strings;

pbValueData = NULL

cbValueData = 0.

The registered names are searched before the pre-installed names

CRYPT_LOCALIZED_NAME_ ENCODING_TYPE | 0
CRYPT_LOCALIZED_NAME_ OID | "LocalizedNames"
CRYPT_OID_FIND_LOCALIZED_ NAME_FUNC | "CryptDLLFindLocalizedName"

Example

// EXAMPLE CODE FOR USING CryptFindLocalizedName().
// Assume that the application has a pointer (pwszCryptName)
// to a specific name.
// Set up the variables.
LPCWSTR pwszCryptName;   // Pointer to a null terminated
                         //   string containing the
                         //   specified name
LPCWSTR lpResult;        // Return pointer to the found
                         //  localized name
// Function call to CryptFindLocalizedName.
lpResult= CryptFindLocalizedName(
        pwszCryptName);  // in - A pointer to a specified
                         //   name defined elsewhere
cout<< "CryptFindLocalizedName;"<< endl<< endl;
if (lpResult) {          // returned value is a Pointer
                         //   to a found localized name
   cout<< "localized name at "<< lpResult<< endl
       << "the localized name is "<< &lpResult<< endl;
}
else {                   // returned value is NULL
   cout<< "no localized name found"<< endl<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSetOIDFunctionValue


CryptHashCertificate

The CryptHashCertificate function hashes the entire encoded content, including the signature.

#include <wincrypt.h>
BOOL WINAPI CryptHashCertificate(
  HCRYPTPROV hCryptProv,     // in
  ALG_ID Algid,              // in
  DWORD dwFlags,             // in
  const BYTE *pbEncoded,     // in
  DWORD cbEncoded,           // in
  BYTE *pbComputedHash,      // out
  DWORD *pcbComputedHash     // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use to compute the hash.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

Algid
Specifies the CryptoAPI hash algorithm to use. If Algid is zero, the default hash algorithm, SHA1, is used.
dwFlags
These flags are passed through to CryptCreateHash. See it for details.
pbEncoded
The address of the encoded content that is to be hashed.
cbEncoded
The size, in bytes, of the encoded content.
pbComputedHash
Pointer to a buffer that receives the computed hash.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbComputedHash
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, the variable pointed to by the pcbComputedHash parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pbComputedHash is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptGetHashParam and CryptHashData may be propagated to this function.

Example

// EXAMPLE CODE FOR USING CryptHashCertificate() to
// hash a certificate for which a certificate context has already
// been obtained (pCertContext).
PCCERT_CONTEXT pCertContext; // Initialized elsewhere

// First, get a cryptographic provider.
HCRYPTPROV hCryptProv = NULL; // Handle returned here
BOOL fReturn = FALSE;

fReturn = CryptAcquireContext(
          &hCryptProv,         // Address for handle to be returned.
          NULL,                // Use the current user's logon name.
          NULL,                // Use the default provider.
          PROV_RSA_FULL,       // Need to do both encrypt & sign.
          NULL);               // No flags needed.
if(TRUE != fReturn)
    printf("Couldn't Get a Cryptographic Provider");

// If the function succeeded, the handle to the cryptographic
// provider resides at hCryptProv.

DWORD  maxSHAhashlen = 20; // The max size hash for SHA is 20 bytes.
BYTE * pbComputedHash;     // Buffer pointer.

// Allocate the memory for the computed hash.
pbComputedHash = (BYTE *)malloc(maxSHAhashlen );

// Hash the certificate using SHA for the hashing algorithm.
fReturn = CryptHashCertificate(hCryptProv, CALG_SHA, 0,
                               pCertContext->pbCertEncoded,
                               pCertContext->cbCertEncoded,
                               pbComputedHash , &maxSHAhashlen );

// Use the hash as desired…

// Free memory allocated when through.
free(pbComputedHash);

// Note : An alternate way of obtaining the CALG_SHA hash is to
// make a call to CertGetCertificateContextProperty specifying
// CERT_SHA1_HASH_PROP_ID which calculates the hash if it has not
// already been calculated. If it already has been calculated,
// a throughput benefit is realized.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptHashPublicKeyInfo, CryptHashToBeSigned


CryptHashPublicKeyInfo

The CryptHashPublicKeyInfo function encodes the public key information and computes its hash.

#include <wincrypt.h>
BOOL WINAPI CryptHashPublicKeyInfo(
  HCRYPTPROV hCryptProv,        // in
  ALG_ID Algid,                 // in
  DWORD dwFlags,                // in
  DWORD dwCertEncodingType,     // in
  PCERT_PUBLIC_KEY_INFO pInfo,  // in
  BYTE *pbComputedHash,         // out
  DWORD *pcbComputedHash        // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use to compute the hash.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

Algid
Specifies the CryptoAPI hash algorithm to use. If Algid is zero, the default hash algorithm, SHA1, is used.
dwFlags
Normally zero. Gets passed on to CryptCreateHash.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pInfo
A pointer to the public key information to be encoded and hashed.
pbComputedHash
Pointer to a buffer that receives the computed hash.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbComputedHash
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, the variable pointed to by the pcbComputedHash parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pbComputedHash is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptGetHashParam and CryptHashData may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Public key ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_MORE_DATA | If the buffer specified by the pbComputedHash parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbComputedHash.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.

Example

// EXAMPLE CODE FOR USING CryptHashPublicKeyInfo().
// Encodes the public key information and computes its hash.
// Assume that a pointer to the Public Key blob (pInfo) has
// already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;    // Service Provider handle- normally 0
ALG_ID Algid = 0;             // Algorithm
DWORD dwFlags = 0;            // Flags value- normally 0
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                              // Type of encoding
PCERT_PUBLIC_KEY_INFO pInfo;  // Pointer to public key info
BYTE * pbComputedHash;        // Pointer to computed hash
DWORD cbComputedHash;         // Size of computer hash
BOOL fResult;                 // Return TRUE if function succeeded
                              //   FALSE if function failed

// Function called the first time to get
// the size of the returned hash.
fResult= CryptHashPublicKeyInfo(
           hCryptProv,
           Algid,
           dwFlags,
           dwCertEncodingType,
           pInfo,
           NULL,              // NULL on first call
                              //   NULL is used to determine the
                              //   size needed to insure that the
                              //   returned data fits in the
                              //   specified buffer
           &cbComputedHash);

if (!fResult){
  cout<< "first call to CryptHashPublicKeyInfo failed"<< endl;
}
else {
  cout<< "first call to CryptHashPublicKeyInfo successful"<< endl;
  pbComputedHash = (BYTE *)malloc (cbComputedHash);
  cout<< "memory allocated"<< endl;
}

// Function call to get the computed hash
fResult= CryptHashPublicKeyInfo(
           hCryptProv,        // in - 0 is default RSA or DSS provider
           Algid,             // in - 0 is default
           dwFlags,           // in - set to 0
           dwCertEncodingType,// in - X509_ASN_ENCODING
           pInfo,             // in - Public key info
           pbComputedHash,    // out- Pointer to the returned hash
           &cbComputedHash);  // in/out - Size of hash

if (!fResult) {               // FALSE
 cout<< "Function failed"<< endl
     << "error = "<< GetLastError()<< endl;
}
else {                        // TRUE
 cout<< "Function succeeded"<< endl;
}
free (pInfo);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptHashCertificate, CryptHashToBeSigned


CryptHashToBeSigned

The CryptHashToBeSigned function computes the hash of the encoded content from a signed and encoded certificate. The data structure is "to be signed" encoded content and its signature.

#include <wincrypt.h>
BOOL WINAPI CryptHashToBeSigned(
  HCRYPTPROV hCryptProv,         // in
  DWORD dwCertEncodingType,      // in
  const BYTE *pbEncoded,         // in, constant
  DWORD cbEncoded,               // in
  BYTE *pbComputedHash,          // out
  DWORD *pcbComputedHash         // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use to compute the hash.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbEncoded
The address of the content that is to be hashed (the encoded CERT_SIGNED_CONTENT_INFO).
cbEncoded
Size, in bytes, of the encoded CERT_SIGNED_CONTENT_INFO.
pbComputedHash
Pointer to a buffer that receives the computed hash.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbComputedHash
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, the variable pointed to by the pcbComputedHash parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pbComputedHash is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptGetHashParam and CryptHashData may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_MORE_DATA | If the buffer specified by the pbComputedHash parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbComputedHash.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.
NTE_BAD_ALGID | The signature algorithm's Object Identifier doesn't map to a known or supported hash algorithm.

Example

// EXAMPLE CODE FOR USING CryptHashToBeSigned().
// From a signed and encoded certificate, computes the hash of the
// encoded content that was originally signed (the original "to be
// signed").
// Assume that a pointer to the CERT_SIGNED_CONTENT_INFO
// (*pbEncoded) has already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;    // Service Provider handle- normally 0
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                              // Type of encoding
const BYTE *pbEncoded;        // Address of CERT_SIGNED_CONTENT_INFO
                              //   struct
DWORD cbEncoded;              // size of content
BYTE * pbComputedHash;        // Pointer to computed hash
DWORD cbComputedHash;         // Size of computer hash
BOOL fResult;                 // Return TRUE if function succeeded
                              //   FALSE if function failed

// Function called the first time to get
// the size of cbEncoded.
fResult= CryptHashToBeSigned(
           hCryptProv,
           dwCertEncodingType,
           pbEncoded,
           cbEncoded,
           NULL,              // NULL on first call to determine the
                              //   size needed to insure that the
                              //   returned data fits in the specified
                              //   buffer
           &cbComputedHash);

if (!fResult){
  cout<< "first call to CryptHashToBeSigned failed"<< endl;
}
else {
  cout<< "first call to CryptHashToBeSigned successful"<< endl;
  pbComputedHash = (BYTE *) malloc (cbComputedHash);
  cout<< "memory allocated"<< endl;
}

// Make the call to get the hash.
fResult= CryptHashToBeSigned(
           hCryptProv,        // in - 0 is default RSA or DSS provider
           dwCertEncodingType,// in - X509_ASN_ENCODING
           pbEncoded,         // in - const address
           cbEncoded,
           pbComputedHash,    // out - Pointer to computed hash
           &cbComputedHash);  // in/out - size of computed hash

if (!fResult) {               // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                        // TRUE
 cout<< "Function succeeded"<< endl;
}
free (pbComputedHash);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptHashCertificate, CryptHashPublicKeyInfo


CryptImportPublicKeyInfo

The CryptImportPublicKeyInfo function converts and imports the public key information into the provider and returns a handle to the public key.

#include <wincrypt.h>
BOOL WINAPI CryptImportPublicKeyInfo(
  HCRYPTPROV hCryptProv,          // in
  DWORD dwCertEncodingType,       // in
  PCERT_PUBLIC_KEY_INFO pInfo,    // in
  HCRYPTKEY *phKey                // out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use when importing the public key.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pInfo
Pointer to the public key to import into the provider.
phKey
Pointer to the handle to the imported public key.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptGetUserKey and CryptExportKey may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Public key ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | An installable or registerable import function could not be found for the specified dwCertEncodingType and pInfo->Algorithm.pszObjId.

Example

// EXAMPLE CODE FOR USING CryptImportPublicKeyInfo().
// From a signed and encoded certificate, computes the hash of the
// encoded content that was originally signed (the original "to be
// signed").
// Assume that a pointer to the Public Key blob (pInfo)
// has already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;    // Service Provider handle
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                              // Type of encoding
PCERT_PUBLIC_KEY_INFO pInfo;  // Initialized elsewhere
HCRYPTKEY *phKey;
BOOL fResult;                 // Return TRUE if function succeeded
                              //   FALSE if function failed

fResult= CryptImportPublicKeyInfo(
           hCryptProv,        // in - 0 is default RSA or DSS provider
           dwCertEncodingType,// in - X509_ASN_ENCODING
           pInfo,             // in - Pointer to the public key to
                              //   import
           phKey);            // out- Pointer to the handle to the
                              //   returned public key

if (!fResult) {               // FALSE
  cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                        // TRUE
  cout<< "Function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptExportPublicKeyInfo


CryptImportPublicKeyInfoEx

The CryptImportPublicKeyInfoEx function converts and imports the public key information into the CSP and returns a handle to the public key. Additional parameters (over those specified by CryptImportPublicKeyInfo) that can be used to override defaults are provided to supplement the CERT_PUBLIC_KEY_INFO.

#include <wincrypt.h>
BOOL WINAPI CryptImportPublicKeyInfoEx(
  HCRYPTPROV hCryptProv,            // in
  DWORD dwCertEncodingType,         // in
  PCERT_PUBLIC_KEY_INFO pInfo,      // in
  ALG_ID aiKeyAlg,                  // in
  DWORD dwFlags,                    // in
  void *pvAuxInfo,                  // in, optional
  HCRYPTKEY *phKey                  // out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use when importing the public key.
dwCertEncodingType
Type of encoding used on the certificate. Currently defined encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pInfo
Pointer to the public key to import into the provider. Note that
pInfo->Algorithm.pszObjId and dwCertEncodingType are used in determining the installable CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC to call. If an installable function was not found, an attempt is made to import the key as a RSA Public Key (szOID_RSA_RSA). For szOID_RSA_RSA, aiKeyAlg may be set to CALG_RSA_SIGN or CALG_RSA_KEYX.
aiKeyAlg
CSP specific algorithm that a user may specify to override the default. Defaults to CALG_RSA_KEYX.
dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.
pvAuxInfo
This parameter is reserved for future use and should be set to NULL in the interim.
phKey
Pointer to the handle to the imported public key.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptGetUserKey and CryptExportKey may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Public key ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | An installable or registerable import function could not be found for the specified dwCertEncodingType and pInfo->Algorithm.pszObjId.

Example

// EXAMPLE CODE FOR USING CryptImportPublicKeyInfoEx().
// Convert and import the public key information and return
// a handle to the public key.
// Assume that a pointer to the public key (pInfo) has
// already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;       // Service Provider handle
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                                 // Type of encoding
PCERT_PUBLIC_KEY_INFO pInfo;     // Initialized elsewhere
ALG_ID aiKeyAlg = CALG_RSA_KEYX; // CSP specific algorithm
DWORD dwFlags = 0;               // Flag value
void *pvAuxInfo = NULL;          // Reserved
HCRYPTKEY *phKey;
BOOL fResult;                    // Return TRUE if function succeeded
                                 //   FALSE if function failed
fResult= CryptImportPublicKeyInfoEx(
           hCryptProv, // in - 0 is default RSA or DSS provider
           dwCertEncodingType,
                       // in - X509_ASN_ENCODING
           pInfo,      // in - Pointer to the public key to import
           aiKeyAlg,   // in - Reserved for future use - set to 0
           0,          // in - Reserved for future use - set to NULL
           NULL,       // in/optional
           phKey);     // out- Pointer to the handle to the public key

if (!fResult) {        // FALSE
  cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                 // TRUE
  cout<< "Function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptExportPublicKeyInfoEx


CryptSignAndEncodeCertificate

The CryptSignAndEncodeCertificate function signs and encodes a certificate, certificate request list (CRL), or certificate request. This function performs the following operations:

  1. Calls CryptEncodeObject using lpszStructType to encode the "to be signed" information.
  2. Calls CryptSignCertificate to sign this encoded information.
  3. Calls CryptEncodeObject again, with lpszStructType set to X509_CERT, to further encode the resulting signed, encoded information.
#include <wincrypt.h>
BOOL WINAPI CryptSignAndEncodeCertificate(
  HCRYPTPROV hCryptProv,                            // in
  DWORD dwKeySpec,                                  // in
  DWORD dwCertEncodingType,                         // in
  LPCSTR lpszStructType,                            // in
  void *pvStructInfo,                               // in
  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,  // in
  void *pvHashAuxInfo,                              // in/optional
  PBYTE pbEncoded,                                  // out
  DWORD *pcbEncoded                                 // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use to do the signature.
dwKeySpec
Identifies the private key to use from the provider's container. For example, AT_KEYEXCHANGE or AT_SIGNATURE.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

lpszStructType
For a list of possible types, see the beginning of CryptEncodeObject/CryptDecodeObject Functions.

The most commonly used values for this type follow:

X509_CERT_TO_BE_SIGNED
X509_CERT_CRL_TO_BE_SIGNED
X509_CERT_REQUEST_TO_BE_SIGNED

pvStructInfo
The most commonly used structures follow:

CERT_INFO
CRL_INFO
CERT_REQUEST_INFO

pSignatureAlgorithm
Should be one of the following:

szOID_OIWSEC_sha1RSASign
szOID_RSA_MD5RSA

pvHashAuxInfo
Not currently used. Must be NULL.
pbEncoded
Pointer to a buffer that receives the signed and encoded output.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbEncoded
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When the function returns, the variable pointed to by the pcbEncoded parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pbEncoded is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptSignHash and CryptHashData may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_MORE_DATA | If the buffer specified by the pbEncoded parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbEncoded.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.
NTE_BAD_ALGID | The signature algorithm's Object Identifier doesn't map to a known or supported hash algorithm.

Example

See Certificate Request Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSignCertificate


CryptSignCertificate

The CryptSignCertificate function signs the "to be signed" information in the encoded signed content.

#include <wincrypt.h>
BOOL WINAPI CryptSignCertificate(
  HCRYPTPROV hCryptProv,                            // in
  DWORD dwKeySpec,                                  // in
  DWORD dwCertEncodingType,                         // in
  BYTE *pbEncodedToBeSigned,                        // in, constant
  DWORD cbEncodedToBeSigned,                        // in
  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,  // in
  void *pvHashAuxInfo,                              // in/optional
  BYTE *pbSignature,                                // out
  DWORD *pcbSignature                               // in, out
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use to do the signature.
dwKeySpec
Identifies the private key to use from the provider's container. For example, AT_KEYEXCHANGE or AT_SIGNATURE.
dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbEncodedToBeSigned
The address of the encoded content to be signed.
cbEncodedToBeSigned
The size, in bytes, of the encoded content.
pSignatureAlgorithm
CRYPT_ALGORITHM_IDENTIFIER with a member pszObjId that should be set to one of the following:

szOID_OIWSEC_sha1RSASign
szOID_RSA_MD5RSA

pvHashAuxInfo
Not currently used. Must be NULL.
pbSignature
Pointer to a buffer that receives the signed hash of the content.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbSignature
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pbSignature parameter. When the function returns, the variable pointed to by the pcbSignature parameter contains the number of bytes stored in the buffer. This parameter can be NULL only if pbSignature is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptSignHash and CryptHashData may be propagated to this function. This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbSignature parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbSignature.
NTE_BAD_ALGID | The signature algorithm's Object Identifier doesn't map to a known or supported hash algorithm.

Example

// EXAMPLE CODE FOR USING CryptSignCertificate().
// Signs the encoded signed content.
// Assume that pointers to the encoded content
// (pbEncodedToBeSigned) and the signature algorithm
// (pSignatureAlgorithm) have already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;        // Service Provider handle
DWORD dwKeySpec = AT_KEYEXCHANGE; // Private key
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                                  // Type of encoding
BYTE *pbEncodedToBeSigned;        // Initialized elsewhere
DWORD cbEncodedToBeSigned;        // Size of content (bytes)
PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm;
                                  // Initialized elsewhere
                                  //   Algorithm object identifiers
void *pvHashAuxInfo = NULL;       // Not used- set to NULL
BYTE *pbSignature = NULL;         // Pointer to the signed hash - set
                                  //   to NULL - memory allocation
                                  //   purposes
DWORD cbSignature;                // Signature size (bytes)
BOOL fResult;                     // Return TRUE if function succeeded
                                  //   FALSE if function failed

// Function called the first time to get the pointer
// to the handle to the public key (pcbSignature).
fResult= CryptSignCertificate(
           hCryptProv,
           dwKeySpec,
           dwCertEncodingType,
           pbEncodedToBeSigned,
           cbEncodedToBeSigned,
           pSignatureAlgorithm,
           NULL,             // NULL - set to NULL
           NULL,             // NULL - to determine the size of
                             //   this informaiton - memory allocation
           &cbSignature);
if (!fResult) {              // FALSE
 cout<< "first call to CryptSignCertificate failed"<< endl;
}
else {
 cout<< "first call to CryptSignCertificate successful"<< endl;
 pbSignature = (BYTE *) malloc (cbSignature);
 cout<< "memory allocated"<< endl;
}

// Function call with the address of the signed hash
fResult= CryptSignCertificate(
           hCryptProv,         // in - 0 is default RSA or DSS
                               //   provider
           dwKeySpec,          // in - Key from provider's container
           dwCertEncodingType, // in - X509_ASN_ENCODING
           pbEncodedToBeSigned,// in/constant - Pointer to encoded
                               //   content
           cbEncodedToBeSigned,// in
           pSignatureAlgorithm,// in
           pvHashAuxInfo,      // in/optional
           NULL,
           &cbSignature);      // in/out- Pointer handle to public key

if (!fResult) {                // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                         // TRUE
 cout<< "Function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSignAndEncodeCertificate


CryptVerifyCertificateSignature

The CryptVerifyCertificateSignature function verifies the signature of a subject certificate, certificate request list (CRL), or certificate request by using the public key information.

#include <wincrypt.h>
BOOL WINAPI CryptVerifyCertificateSignature(
  HCRYPTPROV hCryptProv,            // in
  DWORD dwCertEncodingType,         // in
  BYTE *pbEncoded,                  // in, constant
  DWORD cbEncoded,                  // in
  PCERT_PUBLIC_KEY_INFO pPublicKey  // in
);

Parameters

hCryptProv
Specifies the Cryptographic Service Provider to use when verifying the signature.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbEncoded
The address of the encoded content (an encoded CERT_SIGNED_CONTENT_INFO structure) on which the signature is to be verified.
cbEncoded
The size, in bytes, of the encoded content.
pPublicKey
A pointer to the specified public key to use when verifying the signature.

Return Values

Returns TRUE for a valid signature.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptImportKey, CryptVerifySignature, and CryptHashData may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Name ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | Invalid certificate encoding type. Currently only X509_ASN_ENCODING is supported.
NTE_BAD_ALGID | The signature algorithm's Object Identifier doesn't map to a known or supported hash algorithm.
NTE_BAD_SIGNATURE | The signature was not verified.

Example

// EXAMPLE CODE FOR USING CryptVerifyCertificateSignature().
// Verifies the signature of a subject certificate, certificate
// request list (CRL), or certificate request.
// Assume that pointers to the encoded content (pbEncoded)
// and the public key (pPublicKey) have already been defined.

// Set up the variables.
HCRYPTPROV hCryptProv = 0;        // Service Provider handle
DWORD dwCertEncodingType = X509_ASN_ENCODING;
                                  // Type of encoding
BYTE *pbEncoded;                  // Initialized elsewhere
DWORD cbEncoded;                  // Size of content (bytes)
PCERT_PUBLIC_KEY_INFO pPublicKey; // Initialized elsewhere
BOOL fResult;                     // Return TRUE for a valid signature
                                  //   FALSE for a invalid signature

fResult= CryptVerifyCertificateSignature(
           hCryptProv,        // in - 0 is default RSA or DSS provider
           dwCertEncodingType,// in - X509_ASN_ENCODING
           pbEncoded,         // in/constant - Pointer to encoded
                              //   content
           cbEncoded,         // in - Size of encoded content (bytes)
           pPublicKey);       // in - Pointer to the public key

if (!fResult) {               // FALSE
  cout<< "Invalid signature or error"<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {                        // TRUE
 cout<< "Valid signature"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptEncodeObject/CryptDecodeObject Functions

These are generalized encoding and decoding functions, capable of encoding and decoding certificates, certificate revocation lists (CRL), certificate requests, and certificate extensions.

The function definitions can be found in Wincrypt.h.

Function | Description
CryptDecodeObject | Decodes a structure of type lpszStructType.
CryptDecodeObjectEx | Decodes a structure of type lpszStructType. CryptDecodeObjectEx supports the one pass memory allocation option.
CryptEncodeObject | Encodes a structure of type lpszStructType.
CryptEncodeObjectEx | Encodes a structure of type lpszStructType. CryptEncodeObjectEx supports one pass memory allocation option.

The following table lists predefined constants that are used with encode and decode operations.

Predefined constants for
lpszStructType
PKCS_ATTRIBUTE
PKCS_CONTENT_INFO
PKCS_CONTENT_INFO_SEQUENCE_OF_ANY
PKCS_CTL
PKCS_RC2_CBC_PARAMETERS
PKCS_TIME_REQUEST
PKCS7_SIGNER_INFO
RSA_CSP_PUBLICKEYBLOB
X509_ANY_STRING
X509_BITS
X509_CERT
X509_CERT_CRL_TO_BE_SIGNED
X509_CERT_REQUEST_TO_BE_SIGNED
X509_CERT_TO_BE_SIGNED
X509_CHOICE_OF_TIME
X509_DSS_PARAMETERS
X509_DSS_PUBLICKEY
X509_DSS_SIGNATURE
X509_ENUMERATED
X509_INTEGER
X509_KEYGEN_REQUEST_TO_BE_SIGNED
X509_MULTI_BYTE_INTEGER
X509_MULTI_BYTE_UINT
X509_NAME
X509_NAME_VALUE
X509_OCTET_STRING
X509_PUBLIC_KEY_INFO
X509_SEQUENCE_OF_ANY
X509_UNICODE_ANY_STRING
X509_UNICODE_NAME
X509_UNICODE_NAME_VALUE

The following table lists the extensions and attributes that are used with encode and decode operations. Note that the predefined constants and the object identifier strings can be used interchangeably.

Predefined constants for Extensions and attributes for lpszStructType | Object identifier string
PKCS_SMIME_CAPABILITIES szOID_RSA_SMIMECapabilities | "1.2.840.113549.1.9.15"
PKCS_UTC_TIME szOID_RSA_signingTime | "1.2.840.113549.1.9.5"
X509_ALTERNATE_NAME szOID_SUBJECT_ALT_NAME szOID_ISSUER_ALT_NAME szOID_SUBJECT_ALT_NAME2 szOID_ISSUER_ALT_NAME2 | "2.5.29.7" "2.5.29.8" "2.5.29.17" "2.5.29.18"
X509_AUTHORITY_INFO_ACCESS szOID_AUTHORITY_INFO_ACCESS | "1.3.6.1.5.5.7.1.1"
X509_AUTHORITY_KEY_ID szOID_AUTHORITY_KEY_IDENTIFIER | "2.5.29.1"
X509_AUTHORITY_KEY_ID2 szOID_AUTHORITY_KEY_IDENTIFIER2 | "2.5.29.35"
X509_BASIC_CONSTRAINTS szOID_BASIC_CONSTRAINTS | "2.5.29.10"
X509_BASIC_CONSTRAINTS2 szOID_BASIC_CONSTRAINTS2 | "2.5.29.19"
X509_CERT_POLICIES szOID_CERT_POLICIES | "2.5.29.32"
X509_CRL_DIST_POINTS szOID_CRL_DIST_POINTS | "2.5.29.31"
X509_CRL_REASON_CODE szOID_CRL_REASON_CODE | "2.5.29.21"
X509_ENHANCED_KEY_USAGE szOID_ENHANCED_KEY_USAGE | "2.5.29.37"
X509_KEY_ATTRIBUTES szOID_KEY_ATTRIBUTES | "2.5.29.2"
X509_KEY_USAGE szOID_KEY_USAGE | "2.5.29.15"
X509_KEY_USAGE_RESTRICTION szOID_KEY_USAGE_RESTRICTION | "2.5.29.4"
X509_EXTENSIONS szOID_CERT_EXTENSIONS | "1.3.6.1.4.1.311.2.1.14"
szOID_NEXT_UPDATE_LOCATION | "1.3.6.1.4.1.311.10.2"
szOID_SUBJECT_KEY_IDENTIFIER | "2.5.29.14"

The following table lists the Netscape extensions that are used with encode and decode operations. Note that the Netscape predefined constants and object identifier strings can not be used directly with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx. Instead, these extensions require the use of the appropriate constant specified in the section describing each extension.

Predefined constants for Netscape Extensions | Object identifier string
szOID_NETSCAPE_BASE_URL | "2.16.840.1.113730.1.2"
szOID_NETSCAPE_CA_POLICY_URL | "2.16.840.1.113730.1.8"
szOID_NETSCAPE_CA_REVOCATION_URL | "2.16.840.1.113730.1.4"
szOID_NETSCAPE_CERT_RENEWAL_URL | "2.16.840.1.113730.1.7"
szOID_NETSCAPE_CERT_SEQUENCE | "2.16.840.1.113730.2.5"
szOID_NETSCAPE_CERT_TYPE | "2.16.840.1.113730.1.1"
szOID_NETSCAPE_COMMENT | "2.16.840.1.113730.1.13"
szOID_NETSCAPE_REVOCATION_URL | "2.16.840.1.113730.1.3"
szOID_NETSCAPE_SSL_SERVER_NAME | "2.16.840.1.113730.1.12"


CryptDecodeObject

The CryptDecodeObject function decodes a structure of type lpszStructType.

#include <wincrypt.h>
BOOL WINAPI CryptDecodeObject(
  DWORD dwEncodingType,     // in
  LPCSTR lpszStructType,    // in
  const BYTE *pbEncoded,    // in
  DWORD cbEncoded,          // in
  DWORD dwFlags,            // in
  void *pvStructInfo,       // out
  DWORD *pcbStructInfo      // in/out
);

Parameters

dwEncodingType
The type of encoding used. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

lpszStructType
A pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order word specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

For more details, see the table in CryptEncodeObject/CryptDecodeObject Functions that relates object identifier strings and predefined constants to their corresponding data structures.

pbEncoded
A pointer to the encoded structure.
cbEncoded
The number of bytes pointed to by pbEncoded.
dwFlags
CRYPT_DECODE_NOCOPY_FLAG (0x01)
This flag can be set to indicate that "no copy" optimization is enabled. This optimization, where applicable, updates the pvStructInfo fields to point to content residing within pbEncoded instead of making a copy of the content and appending it to pvStructInfo. For applicable cases, less memory needs to be allocated by the calling application and execution is faster since a copy is not being made. Note that the tradeoff when performing a "no copy" decoding is that pbEncoded can't be freed until pvStructInfo is freed.
CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG (0x01000000)
This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default, CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as 8 bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8, and decodes the value as 8 bit characters.
pvStructInfo
Pointer to a buffer that receives the decoded structure. When the buffer that is specified is not large enough to receive the decoded structure, the function sets ERROR_MORE_DATA and stores the required buffer size, in bytes, into the variable pointed to by pcbStructInfo.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbStructInfo
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pvStructInfo parameter. When the function returns, this variable contains the size of the decoded data copied to *pvStructInfo. The size contained in the variable pointed to by pcbStructInfo may indicate a size larger than the decoded structure, as the decoded structure may have pointers to auxiliary data. This size will be the sum of the size needed by the decoded structure and the auxiliary data.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if this function succeeded. FALSE if it failed.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_BAD_ENCODE | An error was encountered while decoding.
CRYPT_E_OSS_ERROR | ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | A decoding function could not be found for the specified dwEncodingType and lpszStructType.
ERROR_MORE_DATA | If the buffer specified by the pvStructInfo parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptEncodeObject


CryptDecodeObjectEx

[This is preliminary documentation and subject to change.]

The CryptDecodeObjectEx function decodes a structure of type lpszStructType. CryptDecodeObjectEx offers a significant performance improvement over CryptDecodeObject by supporting the memory allocation with the CRYPT_DECODE_ALLOC_FLAG.

#include <wincrypt.h>
BOOL WINAPI CryptDecodeObjectEx(
  DWORD dwCertEncodingType,        // in
  LPCSTR lpszStructType,           // in
  const BYTE *pbEncoded,           // in
  DWORD cbEncoded,                 // in
  DWORD dwFlags,                   // in
  PCRYPT_DECODE_PARA pDecodePara,  // in, optional
  void *pvStructInfo,              // out, optional
  DWORD *pcbStructInfo             // in, out
);

Parameters

dwCertEncodingType
Type of encoding used. If the low-order word containing the certificate encoding type is nonzero, it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Certificate Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

lpszStructType
Pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order word specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

For more details, see the table in CryptEncodeObject/CryptDecodeObject Functions that relates object identifier strings and predefined constants to their corresponding data structures.

pbEncoded
Pointer to the data to be decoded. The structure must be of the type specified by lpszStructType.
cbEncoded
Number of bytes pointed to by pbEncoded. This is the number of bytes to be decoded.
dwFlags
Flag values.

The following flags can be combined with a bitwise OR operation into CryptDecodeObjectEx dwFlags.

CRYPT_DECODE_ALLOC_FLAG
The called decoding function allocates memory for the decoded structure. A pointer to the allocated structure is returned in pvStructInfo.

If pDecodePara or pDecodePara->pfnAlloc is NULL, then, LocalAlloc is called for the allocation and LocalFree must be called to free the memory.

If pDecodePara and pDecodePara->pfnAlloc are non NULL, then pDecodePara->pfnAlloc is called for the allocation and the function pointed to by pDecodePara->pfnFree must be called to free the memory.

CRYPT_DECODE_NOCOPY_FLAG
This flag can be set to enable a "no copy" optimization. This optimization updates the pvStructInfo fields to point to content residing within pbEncoded instead of making a copy of the content and appending it to pvStructInfo. The calling application needs to allocate less memory and execution is faster because a copy is not made. Note that when performing a "no copy" decoding, pbEncoded can't be freed until pvStructInfo is freed.
CRYPT_UNICODE_NAME_DECODE_DISABLE_IE4_UTF8_FLAG
This flag is applicable when decoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. By default, CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as 8 bit characters. If this flag is set, it skips the initial attempt to decode the value as UTF8, and decodes the value as 8 bit characters.
pDecodePara
Pointer to the CRYPT_DECODE_PARA structure containing the encoded paragraph information. If pDecodePara is set to NULL, the LocalAlloc and LocalFree are used to allocate and free memory. If pDecodePara points to a CRYPT_DECODE_PARA structure that function can pass in the callback function to allocate and free memory. This function overrides the default memory allocation of LocalAlloc and LocalFree.
pvStructInfo
Pointer to a buffer that receives the decoded structure. When the buffer that is specified is not large enough to receive the decoded structure, the function sets ERROR_MORE_DATA and stores the required buffer size, in bytes, into the variable pointed to by pcbStructInfo.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

When the CRYPT_DECODE_ALLOC_FLAG is set, pvStructInfo is the address of a pointer to the buffer that will be updated. Because memory is allocated and its pointer is stored at *pvStructInfo, pvStructInfo must always be non-NULL.

pcbStructInfo
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pvStructInfo parameter. When the function returns, the variable pointed to by the pcbStructInfo parameter contains the number of bytes stored in the buffer. The size contained in the variable pointed to by pcbStructInfo may indicate a size larger than the decoded structure, as the decoded structure may have pointers to auxiliary data. This size will be the sum of the size needed by the decoded structure and the auxiliary data. This parameter can be NULL, only if pvStructInfo is NULL.

When the CRYPT_DECODE_ALLOC_FLAG is set, pcbStructInfo is the address of a pointer to the DWORD that will be updated.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. The function has the following error codes:

Error code | Description
CRYPT_E_BAD_ENCODE | An error was encountered while decoding.
CRYPT_E_OSS_ERROR | ASN.1 encoding error. Note, to get the OSS error subtract the value in CRYPT_E_OSS_ERROR from the returned error value and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | A decoding function could not be found for the specified dwCertEncodingType and lpszStructType.
ERROR_MORE_DATA | If the buffer specified by the pvStructInfo parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, in the variable pointed to by pcbStructInfo.

Example

// EXAMPLE CODE FOR USING CryptDecodeObjectEx().
// Assume that pointers to the data to be decoded
// (pbEncoded) and the # of bytes to be decoded (cbEncoded)
// are initialized elsewhere.
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

// Declare and initialize.
const BYTE *pbEncoded;         // Initialized elsewhere
DWORD cbEncoded;               // Initialized elsewhere
PCRYPT_DECODE_PARA DecodePara;
void *pvStructInfo;
DWORD cbStructInfo;
BOOL fResult;
DecodePara->cbSize= sizeof(PCRYPT_DECODE_PARA);

// CryptDecodeObjectEx function call.
fResult= CryptDecodeObjectEx(
          MY_ENCODING_TYPE,    // in- Encoding/decoding type.
          X509_NAME,           // in- Struct type
          pbEncoded,           // in- Data to be decoded.
          cbEncoded,           // in- # of bytes of pbEncoded.
          CRYPT_DECODE_ALLOC_FLAG,
                               // in- dwFlags
          NULL,                // in, optional- DecodePara set to NULL
                               //   to use default memory allocation
                               //   of+ LocalAlloc and LocalFree.
          (void*) &pvStructInfo,
                               // out, optional- pvStructInfo
          &cbStructInfo);      // in, out- pvStructInfo size

if(!fResult) {                 // FALSE returned- function failed.
    printf("The call to CryptDecodeObjectEx failed.\n");
}

else {                         // TRUE returned- function successful.
    printf("The call to CryptDecodeObjectEx successful.\n");
}

// Free the memory.
LocalFree(pvStructInfo);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject


CryptEncodeObject

The CryptEncodeObject function encodes a structure of type lpszStructType.

#include <wincrypt.h>
BOOL WINAPI CryptEncodeObject(
  DWORD dwEncodingType,      // in
  LPCSTR lpszStructType,     // in
  const void *pvStructInfo,  // in
  BYTE *pbEncoded,           // out
  DWORD *pcbEncoded          // in/out
);

Parameters

dwEncodingType
The type of encoding used. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

lpszStructType
A pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order word specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

For more details, see the table in CryptEncodeObject/CryptDecodeObject Functions that relates object identifier strings and predefined constants to their corresponding data structures.

pvStructInfo
A pointer to the structure to be encoded. The structure must be of a type specified by lpszStructType.
pbEncoded
Pointer to a buffer that receives the encoded structure. When the buffer that is specified is not large enough to receive the decoded structure, the function sets ERROR_MORE_DATA and stores the required buffer size, in bytes, into the variable pointed to by pcbEncoded.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbEncoded
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When the function returns, this variable contains the size of the encoded data copied to *pbEncoded. This parameter can be NULL, only if pbEncoded is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if this function succeeded. FALSE if this function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_BAD_ENCODE | An error was encountered while encoding.
CRYPT_E_OSS_ERROR | ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | An encoding function could not be found for the specified dwEncodingType and lpszStructType.
ERROR_MORE_DATA | If the buffer specified by the pbEncoded parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, in the variable pointed to by pcbEncoded.

Example

See Certificate Request Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptDecodeObject


CryptEncodeObjectEx

[This is preliminary documentation and subject to change.]

The CryptEncodeObjectEx function encodes a structure of type lpszStructType. CryptEncodeObjectEx offers a significant performance improvement over CryptEncodeObject by supporting the memory allocation with the CRYPT_ENCODE_ALLOC_FLAG.

#include <wincrypt.h>
BOOL WINAPI CryptEncodeObjectEx(
  DWORD dwCertEncodingType,        // in
  LPCSTR lpszStructType,           // in
  const void *pvStructInfo,        // in
  DWORD dwFlags,                   // in
  PCRYPT_ENCODE_PARA pEncodePara,  // in, optional
  void *pvEncoded,                 // out
  DWORD *pcbEncoded                // in, out
);

Parameters

dwCertEncodingType
The type of encoding used. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

The following encoding types can be combined with a bitwise OR operation:
Certificate Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

lpszStructType
Pointer to an OID defining the structure type. If the high-order word of the lpszStructType parameter is zero, the low-order word specifies an integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

For more details, see the table in CryptEncodeObject/CryptDecodeObject Functions that relates object identifier strings and predefined constants to their corresponding data structures.

pvStructInfo
Pointer to the structure to be encoded. The structure must be of the type specified by lpszStructType.
dwFlags
Flag values.

The following flags can be combined with a bitwise OR operation into CryptEncodeObjectEx dwFlags.

CRYPT_ENCODE_ALLOC_FLAG
The called encoding function allocates memory for the encoded bytes. A pointer to the allocated bytes is returned in pvEncoded.

If pEncodePara or pEncodePara->pfnAlloc is NULL, then, LocalAlloc is called for the allocation and LocalFree must be called to free the memory.

If pEncodePara and pEncodePara->pfnAlloc are non NULL, then, pEncodePara->pfnAlloc is called for the allocation and the function pointed to by pEncodePara->pfnFree must be called to free the memory.

CRYPT_UNICODE_NAME_ENCODE_ENABLE_T61_UNICODE_FLAG
This flag is applicable when encoding X509_UNICODE_NAME. If this flag is set and all the UNICODE characters are <= 0xFF, the CERT_RDN_T61_STRING is selected instead of the CERT_RDN_UNICODE_STRING.
CRYPT_UNICODE_NAME_ENCODE_DISABLE_CHECK_TYPE_FLAG
This flag is applicable when encoding X509_UNICODE_NAME, X509_UNICODE_NAME_VALUE, or X509_UNICODE_ANY_STRING. If this flag is set, the characters are not checked to see if they are valid for the specified Value Type.
pEncodePara
Pointer to the CRYPT_ENCODE_PARA structure containing the encoded paragraph information. If pEncodePara is set to NULL, the LocalAlloc and LocalFree are used to allocate and free memory. If pEncodePara points to a CRYPT_ENCODE_PARA structure that function can pass in the callback function to allocate and free memory. This function overrides the default memory allocation of LocalAlloc and LocalFree.
pvEncoded
Pointer to a buffer that receives the encoded structure. When the buffer that is specified is not large enough to receive the decoded structure, the function sets ERROR_MORE_DATA and stores the required buffer size, in bytes, into the variable pointed to by pcbEncoded.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

When the CRYPT_ENCODE_ALLOC_FLAG is set, pvEncoded is the address of a pointer to the buffer that will be updated. Because memory is allocated and the pointer is stored at *pvEncoded, pvEncoded must always be non-NULL.

pcbEncoded
Pointer to a DWORD that contains the size, in bytes, of the buffer pointed to by the pvEncoded parameter. When the function returns, the variable pointed to by the pcbEncoded parameter contains the number of allocated, encoded bytes stored in the buffer. This parameter can be NULL, only if pvEncoded is NULL.

When the CRYPT_ENCODE_ALLOC_FLAG is set, pcbEncoded is the address of a pointer to the DWORD that will be updated.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded, FALSE if the function failed.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
CRYPT_E_BAD_ENCODE | An error was encountered while encoding.
CRYPT_E_OSS_ERROR | ASN.1 encoding error. Note, to get the OSS error subtract the value in CRYPT_E_OSS_ERROR from the returned error value and see asn1code.h for details on the error.
ERROR_FILE_NOT_FOUND | An encoding function could not be found for the specified dwCertEncodingType and lpszStructType.
ERROR_MORE_DATA | If the buffer specified by the pbEncoded parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, in the variable pointed to by pcbEncoded.

Remarks

CryptEncodeObjectEx first looks for an installable Ex encode function. If no Ex encode function is found, then the old non-Ex installable function is located.

Example

// EXAMPLE CODE FOR USING CryptEncodeObjectEx().
char *Cert_Sub_Name ="Elizabeth Jackson";
#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

// Initialize a single RDN struture.
CERT_RDN_ATTR rgNameAttr = {
   "2.5.4.3",                 // pszObjId
   CERT_RDN_PRINTABLE_STRING, // dwValueType
   strlen(Cert_Sub_Name),     // value.cbData
   (BYTE *)Cert_Sub_Name};    // value.pbData

// Initialize a structure that includes an array of RDN structures.
CERT_RDN rgRDN[] = {
      1,                      // rgRDN.cRDNAttr
      &rgNameAttr};           // rgRDN.rgRDNAttr

// Initialize a CERT_NAME_INFO structure that includes a CERT_RND.
CERT_NAME_INFO CertName = {
       1,                     // CertName. cRDN = number of elements
                              //   in the CERT_RND's array.
       rgRDN};                // CertName.rgRDN

VOID *pvEncoded;
DWORD cbEncoded;
BOOL fResult;

// CryptEncodeObjectEx function call.
fResult= CryptEncodeObjectEx(
           MY_ENCODING_TYPE,  // in- Encoding/decoding type.
           X509_NAME,         // in- Struct type
           &CertName,         // in- Address of CERT_NAME_INFO
                              //   struct.
           CRYPT_ENCODE_ALLOC_FLAG,
                              // in- dwFlags
           NULL,              // in, optional- EncodePara set to NULL.
                              //   to use default memory allocation of
                              //   LocalAlloc and LocalFree.
           (void*) &pvEncoded,// out- address of a pointer to be
                              //   updated.
           &cbEncoded);       // in, out address of a DWORD to be
                              //   updated.
if (!fResult) {               // FALSE returned- function failed.
    printf("The call to CryptEncodeObjectEx failed.\n\n");
    }
else {                        // TRUE returned- function successful.
    printf("The call to CryptEncodeObjectEx succeeded.\n\n");
    }

// Free the memory.
LocalFree(pvEncoded);
printf("The function ran to completion.\n\n");

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptEncodeObject, CryptDecodeObject, CryptDecodeObjectEx


Encode/Decode Details for Common Data Structures

The following topics provide details on the operation of CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx for given values of lpszStructType.


PKCS_ATTRIBUTE

When PKCS_ATTRIBUTE is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CRYPT_ATTRIBUTE structure. See it for details.


PKCS_CONTENT_INFO

When PKCS_CONTENT_INFO is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, CryptDecodeObjectEx or the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_CONTENT_INFO structure.

Additional Details

For X509_ASN_ENCODING, encoded as a PKCS#7 ContentInfo structure.

The CRYPT_DER_BLOB points to the already encoded ANY content.


PKCS_CONTENT_INFO_SEQUENCE_OF_ANY

When PKCS_CONTENT_INFO_SEQUENCE_OF_ANY is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY structure.

Additional Details

For X509_ASN_ENCODING, encoded as a PKCS#7 ContentInfo structure wrapping a sequence of ANY. The value of the contentType field is pszObjId, while the content field is the following structure:

SequenceOfAny ::= SEQUENCE OF ANY

The CRYPT_DER_BLOBs points to the already encoded ANY content.


PKCS_CTL

When PKCS_CTL or szOID_CTL are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CTL_INFO structure. See it for details.


PKCS_RC2_CBC_PARAMETERS

When PKCS_RC2_CBC_PARAMETERS or szOID_RSA_RC2CBC are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.2.840.113549.3.2"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_RC2_CBC_PARAMETERS structure. See it for details.


PKCS_TIME_REQUEST

When PKCS_TIME_REQUEST is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_TIME_STAMP_REQUEST_INFO structure. See it for additional details.


PKCS7_SIGNER_INFO

When PKCS7_SIGNER_INFO is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CMSG_SIGNER_INFO structure. See it for additional details.


RSA_CSP_PUBLICKEYBLOB

When RSA_CSP_PUBLICKEYBLOB is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

For CryptDecodeObject and CryptDecodeObjectEx:
pvStructInfo points to a Public Key Blob Format immediately followed by a RSAPUBKEY and the modulus bytes.
For CryptEncodeObject and CryptEncodeObjectEx:
pvStructInfo points to a Public Key Blob Format.

Additional Details

For CryptDecodeObject and CryptDecodeObjectEx:
CryptExportKey outputs the StructInfo for a dwBlobType of PUBLICKEYBLOB. CryptImportKey expects the StructInfo when importing a public key.

For dwCertEncodingType = X509_ASN_ENCODING, the RSA_CSP_PUBLICKEYBLOB is encoded as a PKCS #1 RSAPublicKey consisting of a SEQUENCE of a modulus INTEGER and a publicExponent INTEGER. When decoded, if the modulus was encoded as an unsigned integer with a leading 0 byte, the 0 byte is removed before converting to the CSP modulus bytes. Since PKCS#1 doesn't have any intended key usage information, the aiKeyAlg field of the BLOBHEADER structure is always set to CALG_RSA_KEYX.

For CryptEncodeObject and CryptEncodeObjectEx:
CryptExportKey outputs the above StructInfo for a dwBlobType of PUBLICKEYBLOB. CryptImportKey expects the above StructInfo when importing a public key.

For dwCertEncodingType = X509_ASN_ENCODING, the RSA_CSP_PUBLICKEYBLOB is encoded as a PKCS #1 RSAPublicKey consisting of a SEQUENCE of a modulus INTEGER and a publicExponent INTEGER. The modulus is encoded as being an unsigned integer.


X509_ANY_STRING

When X509_ANY_STRING is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CERT_NAME_VALUE. See it for additional details.


X509_BITS

When X509_BITS is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_BIT_BLOB structure.

Additional Details

Used when encoding any arbitrary array of bits. One example of usage is with the szOID_NETSCAPE_CERT_TYPE extension.


X509_CERT

When X509_CERT is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_SIGNED_CONTENT_INFO structure.

Additional Details

The CERT_SIGNED_CONTENT_INFO contains the encoded content that is to be signed, plus its signature, and signature algorithm. The ToBeSigned member is the encoded content output from a previous call to CryptEncodeObject() for one of the following:

X509_CERT_TO_BE_SIGNED (the ToBeSigned member is an encoded CERT_INFO).

X509_CERT_CRL_TO_BE_SIGNED (the ToBeSigned member is an encoded CRL_INFO).

X509_CERT_REQUEST_TO_BE_SIGNED (the ToBeSigned member is an encoded CERT_REQUEST_INFO).

X509_KEYGEN_REQUEST_TO_BE_SIGNED (the ToBeSigned member is an encoded CERT_KEYGEN_REQUEST_INFO).


X509_CERT_CRL_TO_BE_SIGNED

When X509_CERT_CRL_TO_BE_SIGNED is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRL_INFO structure. See it for additional details.


X509_CERT_REQUEST_TO_BE_SIGNED

When X509_CERT_REQUEST_TO_BE_SIGNED is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_REQUEST_INFO structure. See it for additional details.


X509_CERT_TO_BE_SIGNED

When X509_CERT_TO_BE_SIGNED is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_INFO structure. See it for additional details.


X509_CHOICE_OF_TIME

When X509_CHOICE_OF_TIME is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a FILETIME.

Additional Details

For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.


X509_DSS_PARAMETERS

When X509_DSS_PARAMETERS or szOID_OIWSEC_dsa are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.3.14.3.2.12"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_DSS_PARAMETERS structure. See it for additional details.


X509_DSS_PUBLICKEY

When X509_DSS_PUBLICKEY is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_UINT_BLOB structure. See BLOB Structure.

Additional Details

Before encoding, inserts a leading 0x00. After decoding, removes a leading 0x00.


X509_DSS_SIGNATURE

When X509_DSS_SIGNATURE is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to an array of 40 BYTEs. The bytes are ordered as output by the DSS CSP's CryptSignHash() where the lower 20 bytes are the R value, and the higher 20 bytes are the S value. The R and S values are treated as unsigned integers and encoded as a sequence of them.

Additional Details

See Generating DSS Signatures.


X509_ENUMERATED

When X509_ENUMERATED is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to an integer containing the enumerated value.

Additional Details

Used when encoding any arbitrary enumeration. One example of usage is with the X509_CRL_REASON_CODE.


X509_INTEGER

When X509_INTEGER is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to an arbitrary integer of 32 bits or less. The integer is treated as being signed.


X509_KEYGEN_REQUEST_TO_BE_SIGNED

When X509_KEYGEN_REQUEST_TO_BE_SIGNED is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CERT_KEYGEN_REQUEST_INFO structure.

Additional Details

For CryptDecodeObject and CryptDecodeObjectEx the pbEncoded is the "to be signed" plus its signature (output of a X509_CERT CryptEncodeObject).

For CryptEncodeObject and CryptEncodeObjectEx the pbEncoded is just the "to be signed".


X509_MULTI_BYTE_INTEGER

When X509_MULTI_BYTE_INTEGER is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_INTEGER_BLOB structure. See BLOB Structure.

Additional Details

The integer in the blob is treated as being in little endian order.


X509_MULTI_BYTE_UINT

When X509_MULTI_BYTE_UINT is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_UINT_BLOB. See BLOB Structure.

Additional Details

Before encoding, inserts a leading 0x00. After decoding, removes a leading 0x00.


X509_NAME

When X509_NAME is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_INFO structure.

Additional Details

Used to decode/encode the Issuer and Subject members in a certificate (CERT_INFO structure).


X509_NAME_VALUE

When X509_NAME_VALUE is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure.

Additional Details

The name values are unicode strings.

For CryptEncodeObject and CryptEncodeObjectEx:

Value.pbData points to the unicode string.

If Value.cbData = 0, then, the unicode string is NULL terminated.

Otherwise, Value.cbData is the unicode string byte count. The byte count is twice the character count.

If the unicode string contains an invalid character for the specified dwValueType, then, *pcbEncoded is updated with the unicode character index of the first invalid character. LastError is set to:

CRYPT_E_INVALID_NUMERIC_STRING,
CRYPT_E_INVALID_PRINTABLE_STRING, or
CRYPT_E_INVALID_IA5_STRING.

The unicode string is converted before being encoded according to the specified dwValueType. If dwValueType is set to 0, LastError is set to E_INVALIDARG.

If the dwValueType isn't one of the character strings (it's a CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING), then, CryptEncodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING.

For CryptDecodeObject and CryptDecodeObjectEx:

Value.pbData points to a NULL terminated unicode string. Value.cbData contains the byte count of the unicode string excluding the NULL terminator. dwValueType contains the type used in the encoded object. It's not forced to CERT_RDN_UNICODE_STRING. The encoded value is converted to the unicode string according to the dwValueType.

If the encoded object isn't one of the character string types, then, CryptDecodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING. For a non character string, decode using X509_NAME_VALUE or X509_ANY_STRING.


X509_OCTET_STRING

When X509_OCTET_STRING is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_DATA_BLOB structure. See BLOB Structure.

Additional Details

The BLOB Structure contains an octet string, an arbitrary sequence of bytes. A common usage is for some encryption algorithms that take an initialization vector, in the form of an octet string. See CRYPT_ALGORITHM_IDENTIFIER.


X509_PUBLIC_KEY_INFO

When X509_PUBLIC_KEY_INFO is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_PUBLIC_KEY_INFO structure. See it for additional details.


X509_SEQUENCE_OF_ANY

When X509_SEQUENCE_OF_ANY is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_SEQUENCE_OF_ANY structure.

Additional Details

The CRYPT_DER_BLOBs point to the already encoded ANY content.


X509_UNICODE_ANY_STRING

When X509_UNICODE_ANY_STRING is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CERT_NAME_VALUE structure.

Additional Details

The name values are unicode strings.

For CryptEncodeObject and CryptEncodeObjectEx:

Value.pbData points to the unicode string.

If Value.cbData = 0, then, the unicode string is NULL terminated.

Otherwise, Value.cbData is the unicode string byte count. The byte count is twice the character count.

If the unicode string contains an invalid character for the specified dwValueType, then, *pcbEncoded is updated with the unicode character index of the first invalid character. LastError is set to:

CRYPT_E_INVALID_NUMERIC_STRING,
CRYPT_E_INVALID_PRINTABLE_STRING, or
CRYPT_E_INVALID_IA5_STRING.

The unicode string is converted before being encoded according to the specified dwValueType. If dwValueType is set to 0, LastError is set to E_INVALIDARG.

If the dwValueType isn't one of the character strings (it's a CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING), then, CryptEncodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING.

For CryptDecodeObject and CryptDecodeObjectEx:

Value.pbData points to a NULL terminated unicode string. Value.cbData contains the byte count of the unicode string excluding the NULL terminator. dwValueType contains the type used in the encoded object. It's not forced to CERT_RDN_UNICODE_STRING. The encoded value is converted to the unicode string according to the dwValueType.

If the encoded object isn't one of the character string types, then, CryptDecodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING. For a non character string, decode using X509_NAME_VALUE or X509_ANY_STRING.


X509_UNICODE_NAME

When X509_UNICODE_NAME is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_INFO.

Additional Details

For CryptDecodeObject and CryptDecodeObjectEx:

The RDN attribute values are UNICODE strings except for the dwValueTypes of CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING. These dwValueTypes are the same as for a X509_NAME. These values aren't converted to UNICODE.

The RDN attribute value's pbData points to a NULL terminated UNICODE string. The RDN attribute value's cbData contains the byte count of the UNICODE string excluding the NULL terminator. The RDN attribute value's dwValueType contains the type used in the encoded object. It is not forced to CERT_RDN_UNICODE_STRING. The encoded value is converted to the UNICODE string according to the dwValueType.

For CryptEncodeObject and CryptEncodeObjectEx:

The RDN attribute values are UNICODE strings except for the dwValueTypes of CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING. These dwValueTypes are the same as for a X509_NAME. These values aren't expected to be UNICODE.

For the remaining string dwValueTypes, the RDN attribute value's pbData points to the UNICODE string.

If the RDN attribute value's cbData = 0, then, the UNICODE string is NULL terminated.

Otherwise, the RDN attribute value's cbData is the UNICODE string byte count. The byte count is twice the character count, and it excludes the NULL terminator.

If the RDN attribute value's dwValueType = 0 (CERT_RDN_ANY_TYPE), the pszObjId is used to find an acceptable dwValueType. If the UNICODE string contains an invalid character for the found or specified dwValueType, then, *pcbEncoded is updated with the error location of the invalid character. See below for details. For an invalid character, LastError is set to:

CRYPT_E_INVALID_NUMERIC_STRING,
CRYPT_E_INVALID_PRINTABLE_STRING, or
CRYPT_E_INVALID_IA5_STRING.

The UNICODE string is converted before being encoded according to the specified dwValueType or the object identifier's dwValueType.

The CryptEncodeObject and CryptEncodeObjectEx error location indices are returned in *pcbEncoded as follows:

The VALUE_INDEX of the error is located in bits 0 through 15.

The ATTR_INDEX of the error is located in bits 16 through 21.

The RDN_INDEX of the error is located in bits 22 through 31.

Note that bit 0 is the least significant bit of the double word.

The following macros are defined to provide for easy reading of the bit mapped fields for VALUE_INDEX, ATTR_INDEX, and RDN_INDEX from the double word that contains them:

GET_CERT_UNICODE_RDN_ERR_INDEX(X)
GET_CERT_UNICODE_ATTR_ERR_INDEX(X)
GET_CERT_UNICODE_VALUE_ERR_INDEX(X)


X509_UNICODE_NAME_VALUE

When X509_UNICODE_NAME_VALUE is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to CERT_NAME_VALUE structure.

Additional Details

The name values are unicode strings.

For CryptEncodeObject and CryptEncodeObjectEx:

Value.pbData points to the unicode string.

If Value.cbData = 0, then, the unicode string is NULL terminated.

Otherwise, Value.cbData is the unicode string byte count. The byte count is twice the character count.

If the unicode string contains an invalid character for the specified dwValueType, then, *pcbEncoded is updated with the unicode character index of the first invalid character. LastError is set to:

CRYPT_E_INVALID_NUMERIC_STRING,
CRYPT_E_INVALID_PRINTABLE_STRING, or
CRYPT_E_INVALID_IA5_STRING.

The unicode string is converted before being encoded according to the specified dwValueType. If dwValueType is set to 0, LastError is set to E_INVALIDARG.

If the dwValueType isn't one of the character strings (it's a CERT_RDN_ENCODED_BLOB or CERT_RDN_OCTET_STRING), then, CryptEncodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING.

For CryptDecodeObject and CryptDecodeObjectEx:

Value.pbData points to a NULL terminated unicode string. Value.cbData contains the byte count of the unicode string excluding the NULL terminator. dwValueType contains the type used in the encoded object. It's not forced to CERT_RDN_UNICODE_STRING. The encoded value is converted to the unicode string according to the dwValueType.

If the encoded object isn't one of the character string types, then, CryptDecodeObject will return FALSE with LastError set to CRYPT_E_NOT_CHAR_STRING. For a non character string, decode using X509_NAME_VALUE or X509_ANY_STRING.


Encode/Decode Details for Extensions and Attributes

The following topics provide details on the operation of CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx for Extensions and Attributes.


PKCS_SMIME_CAPABILITIES

When PKCS_SMIME_CAPABILITIES or szOID_RSA_SMIMECapabilities are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.2.840.113549.1.9.15"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_SMIME_CAPABILITIES structure.

Additional Details

For CryptEncodeObject and CryptEncodeObjectEx (X509_ASN_ENCODING), Parameters.cbData == 0 causes the encoded parameters to be omitted and not encoded as a NULL (05 00) as is done when encoding a CRYPT_ALGORITHM_IDENTIFIER. This is per the S/MIME specification for encoding capabilities.


PKCS_UTC_TIME

When PKCS_UTC_TIME or szOID_RSA_signingTime are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.2.840.113549.1.9.5"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a FILETIME.

Additional Details

For X509_ASN_ENCODING, it is UTC time encoded as a two-digit year precise to seconds.


X509_ALTERNATE_NAME

When X509_ALTERNATE_NAME, szOID_SUBJECT_ALT_NAME, or szOID_ISSUER_ALT_NAME are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.7" (szOID_SUBJECT_ALT_NAME)
"2.5.29.8" (szOID_SUBJECT_ALT_NAME)

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_ALT_NAME_INFO.

Additional Details

Before encoding, the LPWSTR name choices are converted to IA5 strings. If a string contains an invalid IA5 string, then, *pcbEncoded is updated with the error location of the invalid character and LastError is set to CRYPT_E_INVALID_IA5_STRING.

The CryptEncodeObject or CryptEncodeObjectEx error location indices are returned in *pcbEncoded as follows:

The VALUE_INDEX of the error is located in bits 0 through 15. This is the unicode character index.

The ENTRY_INDEX of the error is located in bits 16 through 23.

Note Bit 0 is the least significant bit of the double word.

The following macros are defined to provide for easy reading of the bit mapped fields for VALUE_INDEX and ENTRY_INDEX from the double word that contains them:

GET_CERT_ALT_NAME_VALUE_ERR_INDEX(X)

GET_CERT_ALT_NAME_ENTRY_ERR_INDEX(X)

The szOID_SUBJECT_ALT_NAME has been superseded by szOID_SUBJECT_ALT_NAME2. New certificate servers are implementing the latter.


X509_AUTHORITY_INFO_ACCESS

When X509_AUTHORITY_INFO_ACCESS or szOID_AUTHORITY_INFO_ACCESS are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.3.6.1.5.5.7.1.1"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_AUTHORITY_INFO_ACCESS structure. See it for additional details.

Additional Details

For CRYPT_E_INVALID_IA5_STRING, the error location is returned in *pcbEncoded by CryptEncodeObject(X509_AUTHORITY_INFO_ACCESS)

Error location consists of:

ENTRY_INDEX - 8 bits << 16

VALUE_INDEX - 16 bits (unicode character index)

See X509_ALTERNATE_NAME for ENTRY_INDEX and VALUE_INDEX error location definition.


X509_AUTHORITY_KEY_ID

When X509_AUTHORITY_KEY_ID or szOID_AUTHORITY_KEY_IDENTIFIER are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.1"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_AUTHORITY_KEY_ID_INFO structure. See it for additional details.

Additional Details

The X509_AUTHORITY_KEY_ID has been superseded by X509_AUTHORITY_KEY_ID2. New certificate servers are implementing the latter.


X509_AUTHORITY_KEY_ID2

When X509_AUTHORITY_KEY_ID2 or szOID_AUTHORITY_KEY_IDENTIFIER2 are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.35"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_AUTHORITY_KEY_ID2_INFO structure.

Additional Details

For CRYPT_E_INVALID_IA5_STRING, the error location is returned in *pcbEncoded by CryptEncodeObject CryptEncodeObjectEx (X509_AUTHORITY_KEY_ID2).

See X509_ALTERNATE_NAME for error location definition.


X509_BASIC_CONSTRAINTS

When X509_BASIC_CONSTRAINTS or szOID_BASIC_CONSTRAINTS are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.10"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_BASIC_CONSTRAINTS_INFO structure. See it for additional details.

Additional Details

The X509_BASIC_CONSTRAINTS has been superseded by X509_BASIC_CONSTRAINTS2. New certificate servers are implementing the latter.


X509_BASIC_CONSTRAINTS2

When X509_BASIC_CONSTRAINTS2 or szOID_BASIC_CONSTRAINTS2 are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.19"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_BASIC_CONSTRAINTS2_INFO structure. See it for additional details.


X509_CERT_POLICIES

When X509_CERT_POLICIES or szOID_CERT_POLICIES are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.32"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_POLICIES_INFO structure. See it for additional details.


X509_CRL_DIST_POINTS

When X509_CRL_DIST_POINTS or szOID_CRL_DIST_POINTS are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.31"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRL_DIST_POINTS_INFO structure.

Additional Details

For CRYPT_E_INVALID_IA5_STRING, the error location is returned in *pcbEncoded by CryptEncodeObject or CryptEncodeObjectEx (X509_CRL_DIST_POINTS).

Error location consists of:

CRL_ISSUER_BIT - 1 bit << 31 (0 for FullName, 1 for CRLIssuer)
POINT_INDEX - 7 bits << 24
ENTRY_INDEX - 8 bits << 16
VALUE_INDEX - 16 bits (unicode character index)

See X509_ALTERNATE_NAME for ENTRY_INDEX and VALUE_INDEX error location defines.


X509_CRL_REASON_CODE

When X509_CRL_REASON_CODE, X509_ENUMERATED, or szOID_CRL_REASON_CODE are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.21"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to an integer containing the enumerated value.

Additional Details

The Integer can be set to one of the following enumerated values:

Reason code | Value
CRL_REASON_UNSPECIFIED | 0
CRL_REASON_KEY_COMPROMISE | 1
CRL_REASON_CA_COMPROMISE | 2
CRL_REASON_AFFILIATION_CHANGED | 3
CRL_REASON_SUPERSEDED | 4
CRL_REASON_CESSATION_OF_OPERATION | 5
CRL_REASON_CERTIFICATE_HOLD | 6
CRL_REASON_REMOVE_FROM_CRL | 8


X509_ENHANCED_KEY_USAGE

When X509_ENHANCED_KEY_USAGE or szOID_ENHANCED_KEY_USAGE are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.37"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_ENHKEY_USAGE or CTL_USAGE (structures are the same but are known by different names). See CTL_USAGE for additional details.


X509_EXTENSIONS

When X509_EXTENSIONS is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

N/A

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_EXTENSIONS structure. See it for additional details.


X509_KEY_ATTRIBUTES

When X509_KEY_ATTRIBUTES or szOID_KEY_ATTRIBUTES are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.2"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_KEY_ATTRIBUTES_INFO structure.


X509_KEY_USAGE

When X509_KEY_USAGE or szOID_KEY_USAGE are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.15"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_BIT_BLOB.

Additional Details

It has the same bit definitions as CERT_KEY_ATTRIBUTES_INFO's IntendedKeyUsage member.


X509_KEY_USAGE_RESTRICTION

When X509_KEY_USAGE_RESTRICTION or szOID_KEY_USAGE_RESTRICTION are used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.4"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_KEY_USAGE_RESTRICTION_INFO structure. See it for additional details.


szOID_CERT_EXTENSIONS

When szOID_CERT_EXTENSIONS is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.3.6.1.4.1.311.2.1.14"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_EXTENSIONS structure.

Additional Details

May be used for one of the attribute types in a certificate request.


szOID_ISSUER_ALT_NAME2

When szOID_ISSUER_ALT_NAME2 is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.18"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_ALT_NAME_INFO structure. See it for additional details.


szOID_NEXT_UPDATE_LOCATION

When szOID_NEXT_UPDATE_LOCATION is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"1.3.6.1.4.1.311.10.2"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_ALT_NAME_INFO structure.

Additional Details

Used with certificate trust lists to get the location for the most recent, time valid CTL. Commonly, the choice used in the CERT_ALT_NAME_INFO is a URL indicating the location.


szOID_SUBJECT_ALT_NAME2

When szOID_SUBJECT_ALT_NAME2 is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.17"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_ALT_NAME_INFO structure.


szOID_SUBJECT_KEY_IDENTIFIER

When szOID_SUBJECT_KEY_IDENTIFIER is used for the lpszStructType with CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx the following details apply.

Object Identifier String

"2.5.29.14"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_DATA_BLOB structure. See BLOB Structure.

Additional Details

The BLOB Structure contains an octet string, an arbitrary sequence of bytes.


Encode/Decode Details for Netscape Extensions

The following topics provide details on the operation of CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx for Netscape Extensions.


szOID_NETSCAPE_BASE_URL

For the szOID_NETSCAPE_BASE_URL extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

When present, this string is added to the beginning of all relative URLs in the certificate. This extension can be considered an optimization to reduce the size of the URL extensions.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.2"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is added to the beginning of all relative URLs in the certificate.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_CA_POLICY_URL

For the szOID_NETSCAPE_CA_POLICY_URL extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

It is a relative or absolute URL that points to a web page describing the policies under which the certificate was issued.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.8"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a relative or absolute URL that points to a web page describing the policies under which the certificate was issued.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_CA_REVOCATION_URL

For the szOID_NETSCAPE_CA_REVOCATION_URL extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

A relative or absolute URL can be used to check the revocation status of any certificates that are signed by the CA that this certificate belongs to. This extension is only valid in CA certificates. The use of this extension is the same as for the szOID_NETSCAPE_REVOCATION_URL extension.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.4"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a relative or absolute URL that can be used to check the revocation status of any certificates that are signed by the CA that this certificate belongs to.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_CERT_RENEWAL_URL

For szOID_NETSCAPE_CERT_RENEWAL_URL extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

A relative or absolute URL points to a certificate renewal form. The renewal form will be accessed with an HTTP GET method using a url that is the concatenation of renewal-url and certificate-serial-number. The certificate-serial-number is encoded as a string of ascii hexadecimal digits. For example, if the netscape-base-url is https://www.certs-r-us.com/, the netscape-cert-renewal-url is cgi-bin/check-renew.cgi?, and the certificate serial number is 173420, the resulting URL would be: https://www.certs-r-us.com/cgi-bin/check-renew.cgi?02a56c The document returned should be an HTML form that will allow the user to request a renewal of their certificate.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.7"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a relative or absolute URL that points to a certificate renewal form.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_CERT_SEQUENCE

For the szOID_NETSCAPE_CERT_SEQUENCE extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to PKCS_CONTENT_INFO_SEQUENCE_OF_ANY.

A sequence of certificates is contained in the CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY structure.

The following details apply:

Object Identifier String

"2.16.840.1.113730.2.5"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY structure. See it for additional details.

Additional Details

For X509_ASN_ENCODING, encoded as a PKCS#7 ContentInfo structure wrapping a sequence of ANY. The value of the contentType field is pszObjId, while the content field is the following structure:

SequenceOfAny ::= SEQUENCE OF ANY

The CRYPT_DER_BLOBs in CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY rgValue point to encoded X509 certificates.


szOID_NETSCAPE_CERT_TYPE

For the szOID_NETSCAPE_CERT_TYPE extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_BITS.

Its value is a bit string, as defined below.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.1"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CRYPT_BIT_BLOB structure.

Additional Details

The following bits are defined:

#define NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE 0x80

#define NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE 0x40

#define NETSCAPE_SSL_CA_CERT_TYPE 0x04


szOID_NETSCAPE_COMMENT

For the szOID_NETSCAPE_COMMENT extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

It is a comment that may be displayed to the user when the certificate is viewed.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.13"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a comment that may be displayed to the user when the certificate is viewed.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_REVOCATION_URL

For the szOID_NETSCAPE_REVOCATION_URL extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

A relative or absolute URL can be used to check the revocation status of a certificate. The revocation check will be performed as an HTTP GET method using a url that is the concatenation of revocation-url and certificate-serial-number. The certificate-serial-number is encoded as a string of ascii hexadecimal digits. For example, if the netscape-base-url is https://www.certs-r-us.com/, the netscape-revocation-url is cgi-bin/check-rev.cgi?, and the certificate serial number is 173420, the resulting URL would be: https://www.certs-r-us.com/cgi-bin/check-rev.cgi?02a56c

The server should return a document with a Content-Type of application/x-netscape-revocation. The document should contain a single ascii digit, '1' if the certificate is not currently valid, and '0' if it is currently valid.

Note that for all of the URLs that include the certificate serial number, the serial number will be encoded as a string that consists of an even number of hexadecimal digits. If the number of significant digits is odd, the string will have a single leading zero to ensure an even number of digits is generated.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.3"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a relative or absolute URL that can be used to check the revocation status of a certificate.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


szOID_NETSCAPE_SSL_SERVER_NAME

For the szOID_NETSCAPE_SSL_SERVER_NAME extension, CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, or CryptDecodeObjectEx can be called with lpszStructType set to X509_ANY_STRING or X509_UNICODE_ANY_STRING.

It is a "shell expression" that can be used to match the hostname of the SSL server that is using this certificate. It is recommended that if the server's hostname does not match this pattern the user be notified and given the option to terminate the SSL connection. If this extension is not present then the CommonName in the certificate subject's distinguished name is used for the same purpose.

The following details apply:

Object Identifier String

"2.16.840.1.113730.1.12"

Corresponding Data Structure being encoded or decoded

pvStructInfo points to a CERT_NAME_VALUE structure. The dwValueType member of the CERT_NAME_VALUE is set to CERT_RDN_IA5_STRING. The Value member's pbData member points to an IA5_STRING that is a "shell expression" that can be used to match the hostname of the SSL server that is using this certificate.

Additional Details

When encoding, use X509_ANY_STRING when the string format in the Value member's pbData member is Ascii, and use X509_UNICODE_ANY_STRING when the string format is UNICODE. For the UNICODE case, before encoding, the string is converted to an IA5_STRING as specified by setting dwValueType to CERT_RDN_IA5_STRING.

For decoding, the user has the option of selecting the format of the string that is output to the CERT_NAME_VALUE structure. Use X509_ANY_STRING when the desired string format is Ascii, and use X509_UNICODE_ANY_STRING when the desired string format is UNICODE.


OID Support Functions

These Win32® functions provide Object Identifier (OID) support. You can use these functions to install, register, and dispatch to OID and encoding type-specific functions. The APIs that make use of these functions are CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, CryptDecodeObjectEx, CertVerifyRevocation, and CertOpenStore. For an overview of this process, see Extending CryptoAPI Functionality

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CryptEnumOIDFunction | Enumerates the OID functions identified by their encoding type, function name, and OID.
CryptEnumOIDInfo | Enumerates the OID Information identified by their group and calls pfnEnumOIDInfo for matches.
CryptFindOIDInfo | Uses the specified key and group to find OID information.
CryptFreeOIDFunctionAddress | Releases the handle count that was incremented and returned by CryptGetOIDFunctionAddress or CryptGetDefaultOIDFunctionAddress.
CryptGetDefaultOIDDllList | Gets the list of registered default Dll entries for the specified function set and encoding type.
CryptGetDefaultOIDFunctionAddress | Either gets the first or next installed DEFAULT function or loads the Dll containing the DEFAULT function.
CryptGetOIDFunctionAddress | Searches the list of installed functions for an encoding type and OID match. If a match isn't found there, then the registry is searched for a match.
CryptGetOIDFunctionValue | Gets the value for the specified encoding type, function name, OID, and value name.
CryptInitOIDFunctionSet | Initializes and returns a handle to the OID function set identified by the function name supplied.
CryptInstallOIDFunctionAddress | Installs a set of callable OID function addresses.
CryptRegisterDefaultOIDFunction | Registers the Dll containing the default function to be called for the specified encoding type and function name.
CryptRegisterOIDFunction | Registers the Dll containing the function to be called for the specified encoding type, function name, and OID.
CryptRegisterOIDInfo | Registers the OID information specified in the CRYPT_OID_INFO structure, persisting it to the registry.
CryptSetOIDFunctionValue | Sets the value for the specified encoding type, function name, OID, and value name.
CryptUnregisterDefaultOIDFunction | Removes the registration for the Dll containing the default function to be called for the specified encoding type and function name.
CryptUnregisterOIDFunction | Removes the registration for the Dll containing the function to be called for the specified encoding type, function name, and OID.
CryptUnregisterOIDInfo | Removes the registration for the specified OID information.


CryptEnumOIDFunction

The CryptEnumOIDFunction function enumerates the OID functions identified by their encoding type, function name, and OID. pfnEnumOIDFunc is called for each OID function matching the input parameters.

#include <wincrypt.h>
BOOL WINAPI CryptEnumOIDFunction(
  DWORD dwEncodingType,                   // in
  LPCSTR pszFuncName,                     // in, optional
  LPCSTR pszOID,                          // in, optional
  DWORD dwFlags,                          // in
  void *pvArg,                            // in
  PFN_CRYPT_ENUM_OID_FUNC pfnEnumOIDFunc  // in
);

Parameters

dwEncodingType
Type of encoding specified. Setting this parameter to CRYPT_MATCH_ANY_ENCODING_TYPE matches any encoding type. Note that if CRYPT_MATCH_ANY_ENCODING_TYPE is not specified, then either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000
CRYPT_MATCH_ANY_ENCODING_TYPE | 0xFFFFFFFF

pszFuncName
Name of the function for which a case insensitive match search is performed. Setting this parameter to NULL results in a match being found for any function name.
pszOID
If the high-order word of pszOID is non-zero, pszOID specifies the object identifier for which a case insensitive match search is performed. If the high-order word of pszOID is zero, pszOID is used to match a numeric object identifier. Setting this parameter to NULL matches any object identifier. Setting this parameter to CRYPT_DEFAULT_OID restricts the enumeration to only the DEFAULT functions.
dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.
pvArg
Pointer to arguments that are passed through to the callback function.
pfnEnumOIDFunc
Callback function that is executed for each OID function matching the input parameters. See "Remarks" for details on the callback typedef.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

Remarks

The following typedef structure applies to pfnEnumOIDFunc.

typedef BOOL (WINAPI *PFN_CRYPT_ENUM_OID_FUNC)(
    IN DWORD dwEncodingType,
    IN LPCSTR pszFuncName,
    IN LPCSTR pszOID,
    IN DWORD cValue,
    IN const DWORD rgdwValueType[],
    IN LPCWSTR const rgpwszValueName[],
    IN const BYTE * const rgpbValueData[],
    IN const DWORD rgcbValueData[],
    IN void *pvArg
 );

Members

dwEncodingType
See the above description for dwEncodingType.
pszFuncName
Name of the OID function.
pszOID
pszOID is a pointer to either an OID string, such as "2.5.29.1", an ASCII string, such as "file", or a numeric string, such as #2000.
cValue
Count of elements in the array of value types.
rgdwValueType[]
Array of value types. Each entry in the array will be one of the value types listed for CryptGetOIDFunctionValue under pdwValueType.
rgpwszValueName[]
Array of null-terminated strings containing the name of the value.
rgpbValueData[]
Array that contains the values corresponding to the names in the rgpwszValueName array elements.
rgcbValueData[]
Array that specifies the size, in bytes, of the corresponding elements in the rgpbValueData array.
pvArg
Arguments that are passed through to the callback function.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptEnumOIDInfo

The CryptEnumOIDInfo function enumerates the OID Information identified by their group and calls pfnEnumOIDInfo for matches.

#include <wincrypt.h>
BOOL WINAPI CryptEnumOIDInfo(
  DWORD dwGroupId,                        // in
  DWORD dwFlags,                          // in
  void *pvArg,                            // in
  PFN_CRYPT_ENUM_OID_INFO pfnEnumOIDInfo  // in
);

Parameters

dwGroupId
Setting dwGroupId to zero matches all groups. Otherwise enumerates entries in the specified group.

Currently defined OID group IDs are shown in the following table:
Group ID | Value
None | 0
CRYPT_HASH_ALG_OID_GROUP_ID | 1
CRYPT_ENCRYPT_ALG_OID_GROUP_ID | 2
CRYPT_PUBKEY_ALG_OID_GROUP_ID | 3
CRYPT_SIGN_ALG_OID_GROUP_ID | 4
CRYPT_RDN_ATTR_OID_GROUP_ID | 5
CRYPT_EXT_OR_ATTR_OID_GROUP_ID | 6
CRYPT_ENHKEY_USAGE_OID_GROUP_ID | 7
CRYPT_POLICY_OID_GROUP_ID | 8

dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.
pvArg
Pointer to arguments that are passed through to the callback function.
pfnEnumOIDInfo
Callback function that is executed for each OID information entry matching the input parameters. See "Remarks" for details on the callback typedef.

Return Values

FALSE when the function has stopped the enumeration.

Remarks

The following typedef structure applies to pfnEnumOIDInfo.

typedef BOOL (WINAPI *PFN_CRYPT_ENUM_OID_INFO)(
    IN PCCRYPT_OID_INFO pInfo
    IN void *pvArg
 );

Members

pInfo
Pointer to the OID information.
pvArg
Arguments that are passed through to the callback function.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptFindOIDInfo

The CryptFindOIDInfo function uses the specified key and group to find OID information.

Default tables are supplied with predefined entries that cover commonly used key and group ID combinations. These tables can be expanded per user need by adding combinations with CryptRegisterOIDInfo. User added combinations can be removed from the tables using CryptUnregisterOIDInfo.

When expanding the tables using CryptRegisterOIDInfo, the new entries can be placed either before or after the predefined entries. It is controlled by CryptRegisterOIDInfo(dwFlags). The placement of registered OID information may affect the result of the find operation, since the tables are searched such that registered entries placed before the predefined entries are checked first for a match, then the predefined entries are checked, and finally, registered entries placed after the predefined entries are checked. The first match found is returned. So, if a registered entry placed before the predefined entries overrides one of the predefined entries, it will be returned from CryptFindOIDInfo when it matches the find criteria (the specified key and group).

#include <wincrypt.h>
PCCRYPT_OID_INFO WINAPI CryptFindOIDInfo(
  DWORD dwKeyType,    // in
  void *pvKey,        // in
  DWORD dwGroupId     // in
);

Parameters

dwKeyType
Specifies the key type to use when finding OID information.

Currently defined key types are shown in the following table:
Key type | Meaning of pvKey
CRYPT_OID_INFO_OID_KEY | pvKey points to a szOID
CRYPT_OID_INFO_NAME_KEY | pvKey points to a wszName
CRYPT_OID_INFO_ALGID_KEY | pvKey points to an ALG_ID
CRYPT_OID_INFO_SIGN_KEY pvKey points to an array of two ALG_IDs where:

ALG_ID[0] is the Hash AlgId

ALG_ID[1] is the PubKey AlgId

pvKey
Depends on the dwKeyType. See it for details.
dwGroupId
Specifies the group ID to use when finding OID information. Setting dwGroupId to zero searches all groups according to the dwKeyType. Otherwise, only the dwGroupId is searched.

See Default CRYPT_OID_INFO Tables by dwGroupId for information on the default tables and their predefined entries.

Return Values

Returns a pointer to a constant data structure of CRYPT_OID_INFO type. The returned pointer MUST NOT be freed. NULL is returned when unable to find any information for the specified key and group.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

ALG_ID, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_OID_INFO, CryptRegisterOIDInfo, CryptUnregisterOIDInfo


CryptFreeOIDFunctionAddress

The CryptFreeOIDFunctionAddress function releases the handle that was incremented and returned by CryptGetOIDFunctionAddress or CryptGetDefaultOIDFunctionAddress. If a Dll was loaded for the function being freed, then it is unloaded. However, before doing the unload, the DllCanUnloadNow function exported by the local Dll is called. It should return S_FALSE to inhibit the unload or S_TRUE to enable the unload. If the Dll doesn't export DllCanUnloadNow, the Dll is unloaded. DllCanUnloadNow has the following signature:

STDAPI DllCanUnloadNow(void);

#include <wincrypt.h>
BOOL WINAPI CryptFreeOIDFunctionAddress(
  HCRYPTOIDFUNCADDR hFuncAddr,  // in
  DWORD dwFlags                 // in
);

Parameters

hFuncAddr
Handle to the function address, previously obtained from a call to CryptGetOIDFunctionAddress or CryptGetDefaultOIDFunctionAddress
dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGetDefaultOIDDllList

The CryptGetDefaultOIDDllList function gets the list of registered default Dll entries for the specified function set and encoding type.

#include <wincrypt.h>
BOOL WINAPI CryptGetDefaultOIDDllList(
  HCRYPTOIDFUNCSET hFuncSet,  // in
  DWORD dwEncodingType,       // in
  LPWSTR pwszDllList,         // out
  DWORD *pcchDllList          // in, out
);

Parameters

hFuncSet
Function set handle previously obtained from a call to CryptInitOIDFunctionSet.
dwEncodingType
Type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pwszDllList
Pointer to a buffer that receives the returned list, which consists of either none, one, or more null-terminated file names. The returned list is terminated with a null entry in the list.
For exampe, L"first.dll" L"\0" L"second.dll" L"\0" L"\0"

This parameter can be NULL to set the number of wide characters in the list for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcchDllList
Pointer to a variable that specifies the size, in wide characters, of the returned list pointed to by pwszDllList parameter. When the function returns, the variable pointed to by the pcchDllList parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pwszDllList is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pwszDllList parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcchDllList.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGetDefaultOIDFunctionAddress

The CryptGetDefaultOIDFunctionAddress function either gets the first or next installed DEFAULT function or loads the Dll containing the DEFAULT function.

#include <wincrypt.h>
BOOL WINAPI CryptGetDefaultOIDFunctionAddress(
  HCRYPTOIDFUNCSET hFuncSet,        // in
  DWORD dwEncodingType,             // in
  LPCWSTR pwszDll,                  // in, optional
  DWORD dwFlags,                    // in
  void **ppvFuncAddr,               // out
  HCRYPTOIDFUNCADDR *phFuncAddr     // in, out
);

Parameters

hFuncSet
A function set handle previously obtained from a call to CryptInitOIDFunctionSet.
dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pwszDll
When this parameter is NULL, a search is performed on the list of installed DEFAULT functions. Otherwise, pwszDll is the name of the Dll to load. Normally, the Dll name is obtained from the list returned by CryptGetDefaultOIDDllList.
dwFlags
The flag values. This parameter is reserved for future use and should be set to zero in the interim.
ppvFuncAddr
When this function is successful, *ppvFuncAddr is updated with the function's address.
phFuncAddr
When pwszDll is NULL, *phFuncAddr must be NULL to get the first installed function. Successive installed functions are obtained by setting *phFuncAddr to the hFuncAddr returned by the previous call. The input *phFuncAddr is always freed via a call to CryptFreeOIDFunctionAddress by this function, even if an error results.

When pwszDll is not NULL, then an attempt is made to load the Dll and the DEFAULT function. *phFuncAddr is ignored upon entry and is not freed via a call to CryptFreeOIDFunctionAddress.

When this function is successful, *phFuncAddr is updated with the function address's handle. The function's handle count is incremented. CryptFreeOIDFunctionAddress needs to be called to release it, or CryptGetOIDFunctionAddress can also be called for a NULL value of pwszDll.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGetOIDFunctionAddress

The CryptGetOIDFunctionAddress function searches the list of registered and installed functions for an encoding type and OID match. If a registry match is found, the Dll containing the function is loaded.

#include <wincrypt.h>
BOOL WINAPI CryptGetOIDFunctionAddress(
  HCRYPTOIDFUNCSET hFuncSet,       // in
  DWORD dwEncodingType,            // in
  LPCSTR pszOID,                   // in
  DWORD dwFlags,                   // in
  void **ppvFuncAddr,              // out
  HCRYPTOIDFUNCADDR *phFuncAddr    // out
);

Parameters

hFuncSet
A function set handle previously obtained from a call to CryptInitOIDFunctionSet.
dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszOID
If the high-order word of the OID is nonzero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the numeric identifier to be used as the object identifier. This resulting OID maps to the function that was either installed or registered with the same OID.
dwFlags
The flag values.
Flag Name | Value | Description
CRYPT_GET_INSTALLED _OID_FUNC_FLAG | 0x1 | Search only the installed list of functions.
ppvFuncAddr
If a match is found, *ppvFuncAddr contains the function address.
phFuncAddr
If a match is found, *phFuncAddr contains the handle of the function address. The function's handle count is incremented. CryptFreeOIDFunctionAddress needs to be called to release it.

Note By default, both the registered and installed function lists are searched. Set CRYPT_GET_INSTALLED_OID_FUNC_FLAG to search only the installed list of functions. This flag would be set by a registered function to get the address of a pre-installed function it was replacing. For example, the registered function might handle a new special case and call the pre-installed function to handle the remaining cases.

Return Values

Returns TRUE if a match is found. Returns FALSE if a match is not found.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGetOIDFunctionValue

The CryptGetOIDFunctionValue function gets the value for the specified encoding type, function name, OID, and value name.

#include <wincrypt.h>
BOOL WINAPI CryptGetOIDFunctionValue(
  DWORD dwEncodingType,        // in
  LPCSTR pszFuncName,          // in
  LPCSTR pszOID,               // in
  LPCWSTR pwszValueName,       // in
  DWORD *pdwValueType,         // out
  BYTE *pbValueData,           // out
  DWORD *pcbValueData          // in, out
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the OID function set.
pszOID
If the high-order word of the OID is nonzero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the numeric identifier to be used as the object identifier.
pwszValueName
Points to a null-terminated UNICODE string containing the name of the value to be queried.
pdwValueType
Points to a variable that receives the value's type. The type returned through this parameter will be one of the following:
Value | Meaning
REG_DWORD | A 32-bit number.
REG_EXPAND_SZ | A null-terminated UNICODE string that contains unexpanded references to environment variables (for example, "%PATH%").
REG_MULTI_SZ | An array of null-terminated UNICODE strings, terminated by two null characters.
REG_SZ | A null-terminated UNICODE string.

The pdwValueType parameter can be NULL if the type is not required.

pbValueData
Points to a buffer that receives the value associated with the pwszValueName parameter. The buffer should be big enough to contain the terminating null character. This parameter can be NULL if the data is not required.

This parameter can be NULL if you want to get the size of the buffer for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbValueData
Points to a variable that specifies the size, in bytes of the buffer pointed to by the pbValueData.

In all cases the value returned in *pcbValueData always includes the size of the terminating null character in the string.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbValueData parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbValueData.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptInitOIDFunctionSet

The CryptInitOIDFunctionSet initializes and returns a handle to the OID function set identified by the supplied function name. If the set already exists, a handle to the existing set is returned. This allows different Dlls to install OID functions, for the same function name.

#include <wincrypt.h>
HCRYPTOIDFUNCSET WINAPI
  LPCSTR pszFuncName,  // in
  DWORD dwFlags        // in
);

Parameters

pszFuncName
The identified OID function set.
dwFlags
The flag values. This parameter is reserved for future use and should be set to zero in the interim.

Return Values

Returns the handle to the OID function set identified by the function name supplied.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptInstallOIDFunctionAddress

The CryptInstallOIDFunctionAddress function installs a set of callable OID function addresses.

#include <wincrypt.h>
BOOL WINAPI CryptInstallOIDFunctionAddress(
  HDMODULE hModule,                    // in
  DWORD dwEncodingType,                // in
  LPCSTR pszFuncName,                  // in
  DWORD cFuncEntry,                    // in
  CRYPT_OID_FUNC_ENTRY rgFuncEntry[],  // in, constant
  DWORD dwFlags                        // in
);

Parameters

hModule
This parameter should be updated with the hModule passed to DllMain to prevent the Dll containing the function addresses from being unloaded by CryptGetOIDFunctionAddress/CryptFreeOIDFunctionAddress. This would be the case when the Dll has also registered OID functions via CryptRegisterOIDFunction.
dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function being installed.
cFuncEntry
A count of the number of array elements in rgFuncEntry[].
rgFuncEntry[]
Specifies an array of CRYPT_OID_FUNC_ENTRY. These entries contain an OID and the starting address of the routine that it correlates to.

DEFAULT functions are installed by setting rgFuncEntry[].pszOID equal to CRYPT_DEFAULT_OID.

dwFlags
The flag values. By default, the functions are installed at the end of the list. To install the functions at the beginning of the list, set the CRYPT_INSTALL_OID_FUNC_BEFORE_FLAG.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CRYPT_OID_FUNC_ENTRY


CryptRegisterDefaultOIDFunction

The CryptRegisterDefaultOIDFunction registers the Dll containing the default function to be called for the specified encoding type and function name.

Unlike CryptRegisterOIDFunction, you can't override the function name needing to be exported by the Dll.

#include <wincrypt.h>
BOOL WINAPI CryptRegisterDefaultOIDFunction(
  DWORD dwEncodingType,  // in
  LPCSTR pszFuncName,    // in
  DWORD dwIndex,         // in
  LPCWSTR pwszDll        // in
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function being registered.
dwIndex
The Dll is inserted before the entry specified by dwIndex.

When dwIndex == 0, the insert is at the beginning the list.

When dwIndex == CRYPT_REGISTER_LAST_INDEX, the insert appends at the end of the list.

pwszDll
pwszDll may contain environment-variable strings, which are expanded via ExpandEnvironmentStrings before loading the Dll.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptRegisterOIDFunction

The CryptRegisterOIDFunction registers the Dll containing the function to be called for the specified encoding type, function name, and OID.

By default the functions are installed at the end of the list. To register the functions before the installed functions, call CryptSetOIDFunctionValue with dwValueType set to REG_DWORD and pwszValueName set to CRYPT_OID_REG_FLAGS_VALUE_NAME.

In addition to registering the DLL, you may override the name of the function to be called. For example,

pszFuncName = "CryptDllEncodeObject",

pszOverrideFuncName = "MyEncodeXyz".

This allows a Dll to export multiple OID functions for the same function name without needing to interpose its own OID dispatcher function.

CRYPT_OID_REG_FLAGS_VALUE_NAME is defined as L"CryptFlags"

#include <wincrypt.h>
BOOL WINAPI CryptRegisterOIDFunction(
  DWORD dwEncodingType,       // in
  LPCSTR pszFuncName,         // in
  LPCSTR pszOID,              // in
  LPCWSTR pwszDll,            // in
  LPCSTR pszOverrideFuncName  // in, optional
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function being registered.
pszOID
The OID correlating to the function to be registered. If the high-order word of the OID is non-zero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the numeric identifier to be used as the object identifier.
pwszDll
The name of the DLL to be registered should be passed in this parameter.

This parameter may contain environment-variable strings, which are expanded via ExpandEnvironmentStrings before loading the Dll.

pszOverrideFuncName
If pszOverrideFuncName is not NULL, this parameter specifies the name of the function exported in the Dll. If pszOverrideFuncName is NULL, then the function name specified by pszFuncName is exported in the Dll.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSetOIDFunctionValue


CryptRegisterOIDInfo

The CryptRegisterOIDInfo function registers the OID information specified in the CRYPT_OID_INFO structure, persisting it to the registry.

The crypt32.dll contains information for the commonly known OIDs. This function allows applications to augment crypt32.dll's OID information. During CryptFindOIDInfo's first call, the registered OID information is installed.

When expanding the tables using CryptRegisterOIDInfo, the new entries can be placed either before or after the predefined entries. It is controlled by CryptRegisterOIDInfo (dwFlags). The placement of registered OID information may affect the result of CryptFindOIDInfo, since the tables are searched such that registered entries placed before the predefined entries are checked first for a match, then the predefined entries are checked, and finally, registered entries placed after the predefined entries are checked. The first match found is returned. So, if a registered entry placed before the predefined entries overrides one of the predefined entries, it will be returned from CryptFindOIDInfo when it matches the find criteria (the specified key and group).

#include <wincrypt.h>
BOOL WINAPI CryptRegisterOIDInfo(
  PCCRYPT_OID_INFO pInfo,     // in
  DWORD dwFlags               // in
);

Parameters

pInfo
OID information to register. Specify the group that the OID information is to be registered for by setting the dwGroupId member in the pInfo. Examples showing how to build the CRYPT_OID_INFO predefined entries for each dwGroupId are given with each (see CRYPT_HASH_ALG_OID_GROUP_ID for example). Extrapolating from them to build user defined entries for registration is straightforward.
dwFlags
Specified flag values.

By default the registered OID information is installed after crypt32.dll's OID entries. Set the CRYPT_INSTALL_OID_INFO_BEFORE_FLAG to install before them.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

ALG_ID,
CRYPT_ALGORITHM_IDENTIFIER,
CRYPT_OID_INFO,
CryptFindOIDInfo,
CryptUnregisterOIDInfo,
 CRYPT_HASH_ALG_OID_GROUP_ID,
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
CRYPT_SIGN_ALG_OID_GROUP_ID,
CRYPT_RDN_ATTR_OID_GROUP_ID,
CRYPT_EXT_OR_ATTR_OID_GROUP_ID,
CRYPT_ENHKEY_USAGE_OID_GROUP_ID,
CRYPT_POLICY_OID_GROUP_ID


CryptSetOIDFunctionValue

The CryptSetOIDFunctionValue function sets the value for the specified encoding type, function name, OID, and value name.

#include <wincrypt.h>
BOOL WINAPI CryptSetOIDFunctionValue(
  DWORD dwEncodingType,  // in
  LPCSTR pszFuncName,    // in
  LPCSTR pszOID,         // in
  LPCWSTR pwszValueName, // in
  DWORD dwValueType,     // in
  BYTE *pbValueData,     // in, constant
  DWORD cbValueData      // in
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function for which the encoding type, OID, and value name is being updated.
pszOID
If the high-order word of the OID is non-zero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the integer identifier to be used as the object identifier.
pwszValueName
Points to a UNICODE string containing the name of the value to set. If a value with this name is not already present, the function creates it.
dwValueType
Specifies the type of information to be stored as the value's data. This parameter can be one of the following values:
Value | Meaning
REG_DWORD | A 32-bit number.
REG_EXPAND_SZ | A null-terminated UNICODE string that contains unexpanded references to environment variables (for example, "%PATH%").
REG_MULTI_SZ | An array of null-terminated UNICODE strings, terminated by two null characters.
REG_SZ | A null-terminated UNICODE string.

pbValueData
Points to a buffer containing the data to be stored for the specified value name.
cbValueData
Specifies the size, in bytes, of the information pointed to by the pbValueData parameter. If the data is of type REG_SZ, REG_EXPAND_SZ, or REG_MULTI_SZ, must include the size of the terminating null wide character.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptUnregisterDefaultOIDFunction

The CryptUnregisterDefaultOIDFunction removes the registration for the Dll containing the default function to be called for the specified encoding type and function name.

#include <wincrypt.h>
BOOL WINAPI CryptUnregisterDefaultOIDFunction(
  DWORD dwEncodingType,  // in
  LPCSTR pszFuncName,    // in
  LPCWSTR pwszDll        // in
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function being unregistered.
pwszDll
The name of the Dll where the function is located.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptUnregisterOIDFunction

The CryptUnregisterOIDFunction removes the registration for the Dll containing the function to be called for the specified encoding type, function name, and OID.

#include <wincrypt.h>
BOOL WINAPI CryptUnregisterOIDFunction(
  DWORD dwEncodingType,  // in
  LPCSTR pszFuncName,    // in
  LPCSTR pszOID          // in
);

Parameters

dwEncodingType
The type of encoding specified. Note that either a certificate or message encoding type is required. If the low-order word containing the certificate encoding type is nonzero, then it is used. Otherwise, the high-order word containing the message encoding type is used. If both are specified, the certificate encoding type in the low-order word is used.

Currently defined encoding types are shown in the following table:
Encoding type | Value
None | 0x00000000
CRYPT_ASN_ENCODING | 0x00000001
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pszFuncName
The name of the function being unregistered.
pszOID
A pointer to the OID corresponding to the name of the function being unregistered. If the high-order word of the OID is non-zero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the integer identifier to be used as the object identifier.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptUnregisterOIDInfo

The CryptUnregisterOIDInfo function removes the registration for the specified OID information. Only the pszOID and dwGroupId members are used to identify the OID information to be unregistered.

#include <wincrypt.h>
BOOL WINAPI CryptUnregisterOIDInfo(
  PCCRYPT_OID_INFO pInfo  // in
);

Parameters

pInfo
Specifies the OID information for which the registration is to be removed. The group that the registration is removed for is specified by the dwGroupId member in the pInfo.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

ALG_ID, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_OID_INFO, CryptFindOIDInfo, CryptRegisterOIDInfo


Low-Level Message Functions

The low-level message functions provide the necessary functionality to encode data for transmission and decode data that has been received. Functionality is also provided to decrypt and verify the signatures of received messages.

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CryptMsgCalculateEncodedLength | Calculates the length of an encoded cryptographic message.
CryptMsgClose | Closes a handle to a cryptographic message.
CryptMsgControl | Performs a special control function after the final CryptMsgUpdate of an encoded or decoded cryptographic message.
CryptMsgCountersign | Countersigns an already existing signature in a message.
CryptMsgCountersignEncoded | Countersigns an already existing signature (encoded SignerInfo, as defined by PKCS #7).
CryptMsgDuplicate | Duplicates a cryptographic message handle by incrementing the reference count. The reference count keeps track of the lifetime of the message.
CryptMsgEncodeAndSignCTL | Encodes the CTL and creates a signed message containing the encoded CTL.
CryptMsgGetAndVerifySigner | Gets and verifies the signer of a cryptographic message.
CryptMsgGetParam | Gets a parameter after encoding or decoding a cryptographic message.
CryptMsgOpenToDecode | Opens a cryptographic message for decoding.
CryptMsgOpenToEncode | Opens a cryptographic message for encoding.
CryptMsgSignCTL | Creates a signed message containing the encoded CTL.
CryptMsgUpdate | Updates the contents of a cryptographic message.
CryptMsgVerifyCountersignatureEncoded | Verify a countersignature in terms of the SignerInfo data structure (as defined by PKCS # 7).


CryptMsgCalculateEncodedLength

The CryptMsgCalculateEncodedLength function calculates the required length for an encoded cryptographic message given the message type, encoding parameters, and total length of the data to be updated. Note that the result might not be the exact length. However, it will always be greater than or equal to the actual length.

#include <wincrypt.h>
DWORD WINAPI CryptMsgCalculateEncodedLength(
  DWORD dwMsgEncodingType,        // in
  DWORD dwFlags,                  // in
  DWORD dwMsgType,                // in
  const void *pvMsgEncodeInfo,    // in
  LPSTR pszInnerContentObjID,     // in/optional
  DWORD cbData                    // in
);

Parameters

dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwFlags
The flag values. Currently defined flags are shown in the following table:
Flag | Value
CMSG_BARE_CONTENT_FLAG | 0x00000001
CMSG_DETACHED_FLAG | 0x00000004
CMSG_CONTENTS_OCTETS_FLAG | 0x00000010

CMSG_BARE_CONTENT_FLAG can be specified for a streamed message to indicate that the streamed output will not have an outer ContentInfo wrapper (as defined by PKCS #7). This makes it suitable to be streamed into an enclosing message.

The CMSG_DETACHED_FLAG indicates that there is detached data being supplied for the subsequent calls to CryptMsgUpdate.

The CMSG_CONTENTS_OCTETS_FLAG should be used when you are calculating the size of a DER encoding of a message which is going to be nested inside an enveloped message. This is particularly useful when streaming is being performed.

dwMsgType
The message type. Currently defined types are shown in the following table. Descriptions of the defined types can be found in CryptMsgOpenToEncode.
Message type | Associated structures | Value
CMSG_DATA | Raw data (no associated structure) | 1
CMSG_SIGNED | CMSG_SIGNER_ENCODE_INFO, CMSG_SIGNED_ENCODE_INFO | 2
CMSG_ENVELOPED | CMSG_ENVELOPED_ENCODE_INFO | 3
CMSG_SIGNED_AND_
ENVELOPED 		Not implemented. 4
CMSG_HASHED | CMSG_HASHED_ENCODE_INFO | 5
CMSG_ENCRYPTED | Not implemented. | 6

pvMsgEncodeInfo
A pointer to the message content. The type depends on the type of the message. For the related structures, see pvMsgEncodeInfo under CryptMsgOpenToEncode.
pszInnerContentObjID
See the description under CryptMsgOpenToEncode.
cbData
The size, in bytes, of the content.

Return Values

Returns the required length for an encoded cryptographic message. Returns a zero if the function fails.

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_INVALIDARG | One or more arguments are invalid.

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgOpenToEncode


CryptMsgClose

The CryptMsgClose function closes a handle to a cryptographic message.

#include <wincrypt.h>
BOOL WINAPI CryptMsgClose(
  HCRYPTMSG hCryptMsg      // in
);

Parameters

hCryptMsg
The cryptographic message handle to be closed.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

LastError is preserved.

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgOpenToEncode, CryptMsgOpenToDecode


CryptMsgControl

The CryptMsgControl function performs a special control function after the final CryptMsgUpdate call on a decoded cryptographic message. The controls include decryption, signature and hash verification, and the addition and deletion of certificates, CRLs, signers, and unauthenticated attributes.

Important changes have been made to the CryptoAPI in order to support S/MIME e-mail interoperability, which affect the handling of enveloped messages. See the Remarks for CryptMsgOpenToEncode for details.

#include <wincrypt.h>
BOOL WINAPI CryptMsgControl(
  HCRYPTMSG hCryptMsg,       // in
  DWORD dwFlags,             // in
  DWORD dwCtrlType,          // in
  const void *pvCtrlPara     // in
);

Parameters

hCryptMsg
Handle to a cryptographic message for which a control is to be applied.
dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.
dwCtrlType
Specifies the type of operation to be performed. Currently defined message control types are shown in the following table.
Message Control type | Value
CMSG_CTRL_VERIFY_SIGNATURE | 1
CMSG_CTRL_DECRYPT | 2
CMSG_CTRL_VERIFY_HASH | 5
CMSG_CTRL_ADD_SIGNER | 6
CMSG_CTRL_DEL_SIGNER | 7
CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR | 8
CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR | 9
CMSG_CTRL_ADD_CERT | 10
CMSG_CTRL_DEL_CERT | 11
CMSG_CTRL_ADD_CRL | 12
CMSG_CTRL_DEL_CRL | 13

pvCtrlPara
For a value of CMSG_CTRL_VERIFY_SIGNATURE in dwCtrlType, pvCtrlPara points to a CERT_INFO structure. It identifies the signer of the message for which the signature is to be verified.

For a value of CMSG_CTRL_DECRYPT in dwCtrlType, pvCtrlPara points to a CMSG_CTRL_DECRYPT_PARA structure used to decrypt the message for the specified recipient. For the case of decoding an streamed enveloped message, this value will initiate the decryption of the streamed content. If any encrypted streamed content has accumulated prior to this call, some or all of the plaintext resulting from the decryption of the ciphertext is passed back to the application through the callback function specified in the call to CryptMsgOpenToDecode. Note that when streaming an enveloped message, CryptMsgControl should not be called until the polling for the availability of the CMSG_ENVELOPE_ALGORITHM_PARAM succeeds or an error will result. See CryptMsgOpenToDecode for a description of that polling.

For a value of CMSG_CTRL_VERIFY_HASH in dwCtrlType, pvCtrlPara is not used, and should be set to NULL. The hash that was computed from the content of the message is compared against the hash that is contained in the message.

For a value of CMSG_CTRL_ADD_SIGNER in dwCtrlType, pvCtrlPara points to a CMSG_SIGNER_ENCODE_INFO structure containing the signer information to be added to the message.

For a value of CMSG_CTRL_DEL_SIGNER in dwCtrlType, pvCtrlPara points to a DWORD containing the index of the signer to be deleted. Note that once a deletion is made, any other signer indices in use for this message are invalidated and will need to be reacquired by calling CryptMsgGetParam.

For a value of CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR in dwCtrlType, pvCtrlPara points to a CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA structure containing the index of the signer and a blob containing the unauthenticated attribute information to be added to the message.

For a value of CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR in dwCtrlType, pvCtrlPara points to a CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA structure which contains the index specifying the signer and the index specifying the unauthenticated attribute (for that signer) to be deleted. Note that once a deletion is made, any other unauthenticated attribute indices in use for this signer are invalidated and will need to be reacquired by calling CryptMsgGetParam.

For a value of CMSG_CTRL_ADD_CERT in dwCtrlType, pvCtrlPara points to a BLOB Structure structure named CRYPT_DATA_BLOB that contains the encoded bytes of the certificate to be added to the message.

For a value of CMSG_CTRL_DEL_CERT in dwCtrlType, pvCtrlPara points to a DWORD containing the index of the certificate to be deleted from the message. Note that once a deletion is made, any other certificate indices in use for this message are invalidated and will need to be reacquired by calling CryptMsgGetParam.

For a value of CMSG_CTRL_ADD_CRL in dwCtrlType, pvCtrlPara points to a BLOB Structure named CRYPT_DATA_BLOB that contains the encoded bytes of the CRL to be added to the message.

For a value of CMSG_CTRL_DEL_CRL in dwCtrlType, pvCtrlPara points to a DWORD containing the index of the CRL to be deleted from the message. Note that once a deletion is made, any other CRL indices in use for this message are invalidated and will need to be reacquired by calling CryptMsgGetParam.

Return Values

If the function being performed per the dwCtrlType fails, the return value is FALSE (zero). If it succeeds, the return value is true (non-zero).

When an streamed enveloped message is being decoded, errors encountered in the application defined callback function specified by pStreamInfo in CryptMsgOpenToDecode may be propagated to CryptMsgControl. If this happens, SetLastError is not called by CryptMsgControl after the callback returns, which preserves any errors encountered under the control of the application. It is the responsibility of the callback function (or one of the APIs that it calls) to call SetLastError if an error occurs while the application is processing the streamed data.

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_CONTROL_TYPE | The control type is not valid.
for dwCtrlType == CMSG_CTRL_VERIFY_SIGNATURE |
CRYPT_E_AUTH_ATTR_MISSING | The message does not contain an expected authenticated attribute.
CRYPT_E_BAD_ENCODE | An error was encountered while encoding or decoding.
CRYPT_E_HASH_VALUE | The hash value is not correct.
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_SIGNER_NOT_FOUND | The specified signer for the message was not found.
CRYPT_E_UNEXPECTED_ENCODING | The message is not encoded as expected.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from: CryptCreateHash CryptHashData CryptGetHashParam CryptImportKey CryptVerifySignature
for dwCtrlType == CMSG_CTRL_DECRYPT |
CRYPT_E_ALREADY_DECRYPTED | The message content has already been decrypted.
CRYPT_E_INVALID_INDEX | The index value is not valid.
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_RECIPIENT_NOT_FOUND | The enveloped data message does not contain the specified recipient.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from: CryptGetUserKey CryptImportKey CryptDecrypt
for dwCtrlType == CMSG_CTRL_VERIFY_HASH |
CRYPT_E_HASH_VALUE | The hash value is not correct.
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from: CryptGetHashParam
for dwCtrlType == CMSG_CTRL_ADD_SIGNER |
CRYPT_E_OID_FORMAT | The object identifier is badly formatted.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from: CryptCreateHash CryptHashData CryptGetHashParam CryptSignHash
for dwCtrlType == CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR |
CRYPT_E_INVALID_INDEX | The index value is not valid.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_OUTOFMEMORY | Ran out of memory.

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptMsgCountersign

The CryptMsgCountersign function countersigns an already existing signature in a message. Countersignatures are used to sign an existing signature's encrypted digest. Countersignatures can be used for various purposes, such as time stamping a message.

#include <wincrypt.h>
BOOL WINAPI CryptMsgCountersign(
  HCRYPTMSG hCryptMsg,                       // in
  DWORD dwIndex,                             // in
  DWORD cCountersigners,                     // in
  PCMSG_SIGNER_ENCODE_INFO rgCountersigners  // in
);

Parameters

hCryptMsg
The cryptographic message handle to be used.
dwIndex
A zero-based index of the signer in the signed or signed-and-enveloped message to be countersigned.
cCountersigners
The number of countersigners in the rgCountersigners array.
rgCountersigners
The array of countersigners (CMSG_SIGNER_ENCODE_INFO structures).

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
ERROR_MORE_DATA | The specified is not large enough to hold the returned data.
Propagated errors that may be encountered: | An error can be propagated from: CryptMsgCountersignEncoded.

Example

See Example Code For Countersigning a Message.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgCountersignEncoded, CryptMsgVerifyCountersignatureEncoded


CryptMsgCountersignEncoded

The CryptMsgCountersignEncoded function countersigns an already existing signature (encoded SignerInfo, as defined by PKCS # 7). Outputs an encoded SignerInfo blob, suitable for use as a countersignature attribute in the unauthenticated attributes of a signed-data or signed-and-enveloped-data message.

#include <wincrypt.h>
BOOL WINAPI CryptMsgCountersignEncoded(
  DWORD dwMsgAndCertEncodingType,             // in
  PBYTE pbSignerInfo,                         // in
  DWORD cbSignerInfo,                         // in
  DWORD cCountersigners,                      // in
  PCMSG_SIGNER_ENCODE_INFO rgCountersigners,  // in
  PBYTE pbCountersignature,                   // out
  PDWORD pcbCountersignature                  // in/out
);

Parameters

dwMsgAndCertEncodingType
Type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbSignerInfo
Pointer to the encoded SignerInfo that is to be countersigned.
cbSignerInfo
Count, in bytes, of the encoded SignerInfo data.
cCountersigners
Number of countersigners in the rgCountersigners array.
rgCountersigners
Array of countersigners to be added.
pbCountersignature
Pointer to a buffer that receives an encoded countersignature attribute as defined in PKCS #9.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbCountersignature
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbCountersignature parameter. When the function returns, the variable pointed to by the pcbCountersignature parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbCountersignature is NULL.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_OID_FORMAT | The object identifier is badly formatted.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from CryptCreateHash CryptHashData CryptGetHashParam CryptSignHash CryptMsgOpenToEncode CryptMsgUpdate An error can be propagated from CryptMsgControl if dwCtrlType == CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR.

Example

// EXAMPLE CODE FOR USING CryptMsgCountersignEncoded().
// Countersigns an already existing signature.
// Assume that pointers to the encoded SignerInfo
// (pbSignerInfo) and the array of countersigners
// (rgCountersigners) have already been defined.

// Set up the variables.
DWORD dwMsgAndCertEncodingType = CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING;
                              // Type of encoding
PBYTE pbSignerInfo;           // Pointer to encoded SignerInfo
DWORD cbSignerInfo = 128;     // #, in bytes, of encoded SignerInfo
DWORD cCountersigners = 3;    // # of countersigners
PCMSG_SIGNER_ENCODE_INFO rgCountersigners;
                              // Pointer to array of countersigners
PBYTE pbCountersignature;     // Pointer to countersignature attribute
PDWORD cbCountersignature;    // Pointer to size, in bytes, of
                              //   pbCountersignature
BOOL fResult;                 // Return TRUE if function succeeds
                              //   FALSE if function fails

// Function called the first time to retrieve a pointer to
// the size of the countersignature (cbCounteresignature)
fResult= CryptMsgCountersignEncoded(
           dwMsgAndCertEncodingType,
           pbSignerInfo,
           cbSignerInfo,
           cCountersigners,
           rgCountersigners,
           NULL,                            // NULL on first call
           cbCountersignature);

if (!fResult){
  cout << "first call to CryptMsgCountersignEncoded failed"<< endl;
}
else {
  cout<< "first call to CryptMsgCountersignEncoded successful"<< endl;
  pbCountersignature = (PBYTE) malloc (*cbCountersignature);
  cout<< "memory allocated"<< endl;
}

// Function call to getSignerInfo blob
fResult= CryptMsgCountersignEncoded(
           dwMsgAndCertEncodingType,       // in
           pbSignerInfo,                   // in
           cbSignerInfo,                   // in
           cCountersigners,                // in
           rgCountersigners,               // in
           pbCountersignature,             // out
           cbCountersignature);            // in/out

if (!fResult) {                            // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                                     // TRUE
 cout<< "Function succeeded"<< endl
     << "size = "<< &cbCountersignature<< endl
     << "countersignature attribute = "<< &pbCountersignature;
}
free (pbCountersignature);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgCountersign, CryptMsgVerifyCountersignatureEncoded


CryptMsgDuplicate

[This is preliminary documentation and subject to change.]

The CryptMsgDuplicate function duplicates a cryptographic message handle by incrementing the reference count. The reference count keeps track of the lifetime of the message.

#include <wincrypt.h>
HCRYPTMSG WINAPI CryptMsgDuplicate(
  HCRYPTMSG hCryptMsg            // in
);

Parameters

hCryptMsg
Handle to the cryptographic message for which the reference count is being incremented.

Return Values

A copy is not made of the message, and the returned handle is the same as the handle that was input.

Remarks

CryptMsgDuplicate is used to increase the reference count on a HCRYPTMSG handle so that multiple calls to CryptMsgClose are required to actually release the handle.

Example

// EXAMPLE CODE FOR USING CryptMsgDuplicate().
// Duplicates a message handle by incrementing its reference count.

// Assume that the application has a handle (hCryptMsg)
// to the message that is to be duplicated.

// Set up the variables.
HCRYPTMSG hCryptMsg;         // Message handle
HCRYPTMSG hResult;           // Duplicated message handle

// Function call to CryptMsgDuplicate to duplicate the handle.
hResult = CryptMsgDuplicate(
            hCryptMsg);      // in- Initialized elsewhere

if (hResult){                // returned value is the handle
  cout<< "CryptMsgDuplicate is successful"<< endl
      << "original handle (hCryptMsg) = "<< hCryptMsg<< endl
      << "Duplicate handle (hResult) = "<< hResult<< endl
      << "Note that they are identical"<< endl
      << "The handle reference count has been incremented"<< endl
      << endl;

  // Free memory. Multiple calls to CryptMsgClose are required to
  // decrement the reference count and actually release the handle.
  CryptMsgClose(hResult);
  CryptMsgClose(hCryptMsg);
  }
else{                        // returned value is NULL
  cout<< "CryptMsgDuplicate is not successful"<< endl<< endl;
  }

QuickInfo

Windows NT: Requires version 4.0 SP3 or later (or version 4.0 with IE 3.02 or later).
Windows: Requires Windows 98 or later.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgClose


CryptMsgEncodeAndSignCTL

The CryptMsgEncodeAndSignCTL function encodes the CTL and creates a signed message containing the encoded CTL.

The pCtlInfo is used to do the encoding. Then CryptMsgSignCTL is called.

#include <wincrypt.h>
BOOL WINAPI CryptMsgEncodeAndSignCTL(
  DWORD dwMsgEncodingType,              // in
  PCTL_INFO pCtlInfo,                   // in
  PCMSG_SIGNED_ENCODE_INFO pSignInfo,   // in
  DWORD dwFlags,                        // in
  BYTE *pbEncoded,                      // out
  DWORD *pcbEncoded                     // in/out
);

Parameters

dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pCtlInfo
A pointer to the CTL_INFO structure used to do the encoding.
pSignInfo
Points to a CMSG_SIGNED_ENCODE_INFO structure which optionally contains an array of a CMSG_SIGNER_ENCODE_INFO structures.

The message can be encoded without any signers if the CMSG_SIGNED_ENCODE_INFO structure's cbSize member is set to the size of the structure and all of the other members are set to zero.

dwFlags
CMSG_ENCODE_SORTED_CTL_FLAG
Set this flag if the CTL entries are to be sorted before encoding. This flag should be set if the CertFindSubjectInSortedCTL or CertEnumSubjectInSortedCTL functions will be called. If the subject identifier for the CTL entries is a hash, such as MD5 or SHA1, then CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG should also be set.
CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG
This flag should be set if the above CMSG_ENCODE_SORTED_CTL_FLAG flag is set, and the identifier for the TrustedSubjects is a hash, such as, MD5 or SHA1.
pbEncoded
Pointer to a buffer that receives the encoded message produced.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbEncoded
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When the function returns, the variable pointed to by the pcbEncoded parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbEncoded is NULL.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
Propagated errors that may be encountered: | An error can be propagated from CryptMsgOpenToEncode CryptMsgUpdate

Example

// EXAMPLE CODE FOR USING CryptMsgEncodeAndSignCTL().
// Encodes the CTL and creates a signed message
// Assume that pointers to the PCTL_INFO structure
// (pCtlInfo), and the CMSG_SIGNED_ENCODE_INFO
// (pSignInfo) have already been defined.

// Set up the variables.
DWORD dwMsgEncodingType = CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING;
                                   // Type of encoding
PCTL_INFO pCtlInfo;                // Pointer to the CTL_INFO
                                   //   structure to do the encoding
PCMSG_SIGNED_ENCODE_INFO pSignInfo;// Pointer to a
                                   //   CMSG_SIGNED_ENCODE_INFO
                                   //   structure
DWORD dwFlags = 0;                 // Reserved - set to 0
BYTE *pbEncoded;                   // Pointer to encoded message
DWORD cbEncoded;                   // Pointer to size, in bytes, of
                                   //   pbEncoded
BOOL fResult;                      // Return TRUE if function succeeds
                                   //   FALSE if function fails

// Function called the first time to get a pointer to
// the size of the encoded message (cbEncoded)
fResult= CryptMsgEncodeAndSignCTL(
           dwMsgEncodingType,
           pCtlInfo,
           pSignInfo,
           0,                        // dwFlags set to 0
           NULL,                     // NULL on first call
           &cbEncoded);

if (!fResult){
  cout << "first call to CryptMsgEncodeAndSignCTL failed"<< endl;
}
else {
  cout<< "first call to CryptMsgEncodeAndSignCTL successful"<< endl;
  pbEncoded = (BYTE*) malloc (cbEncoded);
  cout<< "memory allocated"<< endl;
}

// Function call to a pointer to the encoded message
fResult= CryptMsgEncodeAndSignCTL(
           dwMsgEncodingType,        // in
           pCtlInfo,                 // in
           pSignInfo,                // in
           0,                        // in - Reserved- set to 0
           pbEncoded,                // out
           &cbEncoded);              // in/out

if (!fResult) {                      // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                               // TRUE
 cout<< "Function succeeded"<< endl
     << "size = "<< &cbEncoded<< endl
     << "encoded message at location = "<< pbEncoded<< endl;
}
free (pbEncoded);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CMSG_SIGNED_ENCODE_INFO, CTL_INFO, CryptMsgOpenToEncode, CryptMsgSignCTL, CertFindSubjectInSortedCTL, CertEnumSubjectInSortedCTL


CryptMsgGetAndVerifySigner

The CryptMsgGetAndVerifySigner function gets and verifies the signer of a cryptographic message.

#include <wincrypt.h>
BOOL WINAPI CryptMsgGetAndVerifySigner(
  HCRYPTMSG hCryptMsg,          // in
  DWORD cSignerStore,           // in
  HCERTSTORE *rghSignerStore,   // in, optional
  DWORD dwFlags,                // in
  PCCERT_CONTEXT *ppSigner,     // out,  optional
  DWORD pdwSignerIndex          // in/out, optional
);

Parameters

hCryptMsg
A handle to a cryptographic message.
cSignerStore
The count of stores in rghSignerStore.
rghSignerStore
The array of signer stores.
dwFlags
If CMSG_TRUSTED_SIGNER_FLAG is set, then, treat the signer stores in rghSignerStore as being trusted and only search them to find the certificate corresponding to the signer's issuer and serial number. Otherwise, the signer stores are optionally provided to supplement the message's store of certificates. If a signer certificate is found, its public key is used to verify the message signature.

The CMSG_SIGNER_ONLY_FLAG can be set to return the signer without doing the signature verification.

If CMSG_USE_SIGNER_INDEX_FLAG is set, then, only get the signer specified by *pdwSignerIndex. Otherwise, iterate through all the signers until a signer verifies or until there are no more signers.

ppSigner
See the Remarks below.
pdwSignerIndex
See the Remarks below.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

Remarks

For a verified signature, *ppSigner is updated with the certificate context of the signer and *pdwSignerIndex is updated with the index of the signer. ppSigner and/or pdwSignerIndex can be NULL, indicating the caller isn't interested in getting the certificate context and/or index of the signer.

Example

// EXAMPLE CODE FOR USING CryptMsgGetAndVerifySigner().
// Gets and verifies the cryptographic message.
// Assume that the handle to the crypt message (hCryptMsg)
// and the pointer to the array of signer stores
// (rghSignerStore) have already been defined.

// Set up the variables.
HCRYPTMSG hCryptMsg;             // A handle to the crypt message
DWORD cSignerStore = 128;        // # of stores in SignerStore
HCERTSTORE *rghSignerStore;      // Array of signer rghstores
DWORD dwFlags = CMSG_TRUSTED_SIGNER_FLAG;
                                 // Flag value
PCCERT_CONTEXT *ppSigner = NULL; // Pointer to a certificate context pointer
DWORD *pdwSignerIndex;           // Pointer to the signer index
BOOL fResult;                    // Return TRUE if function succeeds
                                 //   FALSE if function fails

// Function call to get and verify the signer
// of a cryptographic message
fResult= CryptMsgGetAndVerifySigner(
           hCryptMsg,          // in
           cSignerStore,       // in
           rghSignerStore,     // in
           dwFlags,            // in
           ppSigner,           // out
           pdwSignerIndex = NULL);
                               // in/out or set to NULL to indicate no
                               //   interest in getting signer index

if (!fResult){
  cout<< "Call to CryptMsgGetAndVerifySigner failed"<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {
  cout<< "Call to CryptMsgGetAndVerifySigner successful"<< endl
      << "Flag value = "<< dwFlags<< endl
      << "Pointer to the signer of certificate context = "<< &ppSigner<< endl
      << "Index of the signer = "<< &pdwSignerIndex<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CERT_CONTEXT, CTL_CONTEXT, CryptMsgOpenToDecode, CryptMsgControl


CryptMsgGetParam

The CryptMsgGetParam function gets a parameter after encoding/decoding a cryptographic message. This function is called after the final CryptMsgUpdate. For an encoded message, only the CMSG_CONTENT_PARAM and CMSG_COMPUTED_HASH_PARAM are valid.

#include <wincrypt.h>
BOOL WINAPI CryptMsgGetParam(
  HCRYPTMSG hCryptMsg,    // in
  DWORD dwParamType,      // in
  DWORD dwIndex,          // in
  void *pvData,           // out
  DWORD *pcbData          // in/out
);

Parameters

hCryptMsg
A handle to a cryptographic message.
dwParamType
The following list contains the defined parameter types. These parameter types indicate the type of data being requested and correspondingly, the type of data structure to use at pvData to receive it.
CMSG_BARE_CONTENT_PARAM (3)
Used to retrieve the encoded content of an encoded cryptographic message, without the outer layer of CONTENT_INFO. That is, only the encoding of the ContentInfo.content field is returned, as defined in PKCS #7, General syntax. Also used for Microsoft® Internet Explorer version 3.0 compatibility for SPC files.

Applicable only to encode.

pvData points to the buffer receiving the encoded bytes.

CMSG_CERT_COUNT_PARAM (11)
Used to determine the count of Certificates in a received signed message.

Applicable only to decode.

pvData points to a DWORD, which receives the count.

CMSG_CERT_PARAM (12)
Used to retrieve a Certificate when decoding a received signed message.

To get all the Certificates, repetitively call CryptMsgGetParam, while varying dwIndex from 0 to (CertCount - 1), where CertCount is the value obtained from a previous call to CryptMsgGetParam with dwParamType set to CMSG_CERT_COUNT_PARAM.

Applicable only to decode.

pvData points to an array of the certificate's encoded bytes.

CMSG_COMPUTED_HASH_PARAM (22)
This parameter is used when decoding a received hashed message to retrieve the value of the hash that was calculated, based on the data in the message.

Applicable for a HASHED message.

For HASHED, this parameter may be used for either encoding or decoding a message.

Applicable to both encode and decode.

pvData points to an array of bytes.

CMSG_CONTENT_PARAM (2)
When a message has been opened to encode, this parameter is used to retrieve the whole PKCS#7 message.

When a message has been opened to decode, this parameter is used to retrieve the inner content. If the message is enveloped and the inner type is data, the decrypted content is returned if you have already called CryptMsgControl to decrypt it. If the inner type is not data, the encoded blob is returned, which requires further decoding. If the message is not enveloped, and if the inner content is of type DATA, the returned data is the contents octets of the inner content.

Applicable to both encode and decode.

For encode, pvData points to the buffer receiving the encoded bytes.

For decode, pvData points to the buffer receiving the inner content. If the type is CMSG_DATA, the contents octets are returned. If the type is not CMSG_DATA, the encoded inner content is returned.

CMSG_CRL_COUNT_PARAM (13)
Used to determine the count of Certificate Revocation Lists (CRLs) in a received signed message.

Applicable only to decode.

pvData points to a DWORD, which receives the count.

CMSG_CRL_PARAM (14)
Used to retrieve a Certificate Revocation List (CRL) when decoding a received signed message.

To get all the CRLs, repetitively call CryptMsgGetParam, while varying dwIndex from 0 to (CrlCount - 1), where CrlCount is the value obtained from a previous call to CryptMsgGetParam with dwParamType set to CMSG_CRL_COUNT_PARAM.

Applicable only to decode.

pvData points to an array of the CRL's encoded bytes.

CMSG_ENCODED_MESSAGE (29)
Used when it is desired to change the contents of an already encoded message. The message must first be decoded with a call to CryptMsgOpenToDecode. Then the change to the message is made through a call to CryptMsgControl, CryptMsgCountersign, or CryptMsgCountersignEncoded. The message is then encoded again with a call to CryptMsgGetParam, specifying CMSG_ENCODED_MESSAGE to get a new encoding that reflects the changes made. One such purpose for performing this operation is during a time stamping where an attribute may be added to the message.

Applicable only to decode.

pvData points to a buffer that receives the encoded bytes.

CMSG_ENCODED_SIGNER (28)
The encoding of the signer info (CMSG_SIGNER_INFO) for one signer of a signed message.

Applicable only to decode.

pvData points to a buffer receiving the encoded bytes.

CMSG_ENCRYPTED_DIGEST (27)
Used when retrieving the encrypted digest of the signature. Typically used for performing time stamping.

Applicable only to decode.

pvData points to a buffer receiving the encrypted digest bytes.

CMSG_ENVELOPE_ALGORITHM_PARAM (15)
Used to retrieve the ContentEncryptionAlgorithm that was used for a ENVELOPED or SIGNED_AND_ENVELOPED received message.

Applicable only to decode.

pvData points to an CRYPT_ALGORITHM_IDENTIFIER struct.

CMSG_HASH_ALGORITHM_PARAM (20)
This parameter is used when decoding a received hashed message to retrieve the HashAlgorithm that was used to hash the message when it was created.

Applicable only to decode.

pvData points to an CRYPT_ALGORITHM_IDENTIFIER struct.

CMSG_HASH_DATA_PARAM (21)
This parameter is used when decoding a received hashed message to retrieve the value of the hash that was stored in the message when it was created.

Applicable only to decode.

pvData points to an array of bytes.

CMSG_INNER_CONTENT_TYPE_PARAM (4)
Used to determine the inner content type of a received message. Returns the type of the inner content of a decoded cryptographic message, in the form of a NULL-terminated object identifier string (for example: "1.2.840.113549.1.7.1").

Applicable only to decode. Not applicable to messages of type DATA.

pvData points to the buffer receiving the object identifier string.

CMSG_RECIPIENT_COUNT_PARAM (17)
Used to determine the count of recipients in an ENVELOPED or SIGNED_AND_ENVELOPED received message.

Applicable only to decode.

pvData points to a DWORD, which receives the count.

CMSG_RECIPIENT_INDEX_PARAM (18)
Used to determine the index of the recipient used to decrypt an ENVELOPED or SIGNED_AND_ENVELOPED message. This parameter is available only after the message has been decrypted.

Applicable only to decode.

pvData points to a DWORD, which receives the count.

CMSG_RECIPIENT_INFO_PARAM (19)
Used to retrieve the CERT_INFO for a recipient when decoding a received signed message.

To get the CERT_INFO for all the recipients, repetitively call CryptMsgGetParam, while varying dwIndex from 0 to (RecipientCount - 1), where RecipientCount is the value obtained from a previous call to CryptMsgGetParam with dwParamType set to CMSG_RECIPIENT_COUNT_PARAM.

Only the following fields have been updated in the CERT_INFO struct: Issuer, SerialNumber.

Applicable only to decode.

pvData points to a CERT_INFO struct.

CMSG_SIGNER_AUTH_ATTR_PARAM (9)
This parameter is used when decoding a received signed message to retrieve the authenticated attributes for the signer of the message.

To get all the authenticated attributes for a given signer, call CryptMsgGetParam, with dwIndex equal to that signer's index.

Applicable only to decode.

pvData points to a CRYPT_ATTRIBUTES struct.

CMSG_SIGNER_CERT_INFO_PARAM (7)
Used to retrieve the CERT_INFO for a signer when decoding a received signed message. Typically, this is done when preparing to get the Certificate for a signer of interest, which requires the signer's Issuer and SerialNumber. To get the CERT_INFOs for all the signers, repetitively call CryptMsgGetParam while varying dwIndex from 0 to (SignerCount - 1), where SignerCount is the value obtained from a previous call to CryptMsgGetParam with dwParamType set to CMSG_SIGNER_COUNT_PARAM.

Only the following fields contain valid data in the CERT_INFO struct returned: Issuer and SerialNumber.

Applicable only to decode.

pvData points to a CERT_INFO struct.

CMSG_SIGNER_COUNT_PARAM (5)
Used to determine the count of signers in a received message of type SIGNED, SIGNED_AND_ENVELOPED.

Applicable only to decode.

pvData points to a DWORD which receives the count.

CMSG_SIGNER_HASH_ALGORITHM_PARAM (8)
This parameter is used when decoding a received signed message to retrieve the HashAlgorithm that was used by a signer of the message.

To get the hash algorithm for a given signer, call CryptMsgGetParam, with dwIndex equal to that signer's index.

Applicable only to decode.

pvData points to a CRYPT_ALGORITHM_IDENTIFIER struct.

CMSG_SIGNER_INFO_PARAM (6)
Used to retrieve a signer when decoding a received signed message. To get all the signers, repetitively call CryptMsgGetParam, while varying dwIndex from 0 to (SignerCount - 1), where SignerCount is the value obtained from a previous call to CryptMsgGetParam with dwParamType set to CMSG_SIGNER_COUNT_PARAM.

Applicable only to decode.

pvData points to a CMSG_SIGNER_INFO struct.

CMSG_SIGNER_UNAUTH_ATTR_PARAM (10)
This parameter is used when decoding a received signed message to retrieve the unauthenticated attributes for the signer of the message.

To get the unauthenticated attributes for a given signer, call CryptMsgGetParam, with dwIndex equal to that signer's index.

Applicable only to decode.

pvData points to a CRYPT_ATTRIBUTES struct.

CMSG_TYPE_PARAM (1)
This parameter is used to retrieve the message type from a decoded message. When a message is received and its type is unknown, this parameter can be passed to retrieve the message type. This retrieved message type can then be compared to supported types to see if processing should be continued. For supported message types see the dwMessageType parameter of the CryptMsgOpenToDecode function.

Applicable only to decode.

pvData points to a DWORD which receives the message type.

dwIndex
The index for the parameter being retrieved, where applicable. When a parameter is not being retrieved, this parameter is ignored and should be set to zero.
pvData
Pointer to a buffer that receives the data retrieved. The form of this data will vary, depending on the parameter type.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbData
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pvData parameter. When the function returns, the variable pointed to by the pcbData parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pvData is NULL.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_ATTRIBUTES_MISSING | The message does not contain the requested attributes.
CRYPT_E_INVALID_INDEX | The index value is not valid.
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_NOT_DECRYPTED | The message content has not been decrypted yet.
CRYPT_E_OID_FORMAT | The object identifier is badly formatted.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_ENCODING | The message is not encoded as expected.
E_INVALIDARG | One or more arguments are invalid.
ERROR_MORE_DATA | The specified is not large enough to hold the returned data.
Propagated errors that may be encountered: | For dwParamType == CMSG_COMPUTED_HASH_PARAM an error can be propagated from: CryptGetHashParam

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgUpdate, CryptMsgOpenToDecode, CryptMsgOpenToEncode


CryptMsgOpenToDecode

The CryptMsgOpenToDecode function opens a cryptographic message for decoding. The message remains open until CryptMsgClose is called.

Important changes have been made to the CryptoAPI in order to support S/MIME e-mail interoperability, which affect the handling of enveloped messages. See the Remarks for CryptMsgOpenToEncode for details.

#include <wincrypt.h>
HCRYPTMSG WINAPI CryptMsgOpenToDecode(
  DWORD dwMsgEncodingType,         // in
  DWORD dwFlags,                   // in
  DWORD dwMsgType,                 // in
  HCRYPTPROV hCryptProv,           // in
  PCERT_INFO pRecipientInfo,       // in/optional
  PCMSG_STREAM_INFO pStreamInfo    // in/optional
);

Parameters

dwMsgEncodingType
Type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwFlags
Flag values. The CMSG_DETACHED_FLAG indicates that there is detached data being supplied for the subsequent calls to CryptMsgUpdate.
dwMsgType
Message type. Currently defined types are shown in the following table.
Message type | Associated structures | Value
CMSG_DATA | Raw data (no associated structure) | 1
CMSG_ENCRYPTED | Not implemented. | 6
CMSG_ENVELOPED | CMSG_ENVELOPED_ENCODE_INFO | 3
CMSG_HASHED | CMSG_HASHED_ENCODE_INFO | 5
CMSG_SIGNED | CMSG_SIGNER_ENCODE_INFO, CMSG_SIGNED_ENCODE_INFO | 2
CMSG_SIGNED_AND_ENVELOPED | Not implemented. | 4

For the Message type descriptions, see CryptMsgOpenToEncode.

Signed messages created with Microsoft® Internet Explorer version 3.0 do not contain header information. To maintain compatibility with Internet Explorer version 3.0, the dwMsgType parameter is provided. Therefore, if a signed message from Internet Explorer version 3.0 is received, the message type must be passed in to the function.

When zero is passed in for the dwMsgType parameter, this function will attempt to read the message type from the header on the message. If the header is missing, as in the case of some Internet Explorer version 3.0 messages, the function call will fail.

hCryptProv
Specifies a handle to the cryptographic provider to use for hashing the message. For signed messages, hCryptProv is used for signature verification.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

pRecipientInfo
This parameter is reserved for future use and should be set to NULL in the interim.
pStreamInfo
When streaming is not being used, this parameter must be set to NULL.

When streaming is being used, this parameter should point to a CMSG_STREAM_INFO structure. The callback specified by pfnStreamOutput in the CMSG_STREAM_INFO structure is called when CryptMsgUpdate is executed (and also when CryptMsgControl is executed when decoding a streamed enveloped message). For more information on how to use the callback, see CMSG_STREAM_INFO.

For a signed message, the callback is passed a block of the decoded bytes from the inner content of the message.

For an enveloped message, periodic checks should be made to see if the CMSG_ENVELOPE_ALGORITHM_PARAM is available yet by calling CryptMsgGetParam (CMSG_ENVELOPE_ALGORITHM_PARAM after each call to CryptMsgUpdate. CryptMsgGetParam will fail with LastError == CRYPT_E_STREAM_MSG_NOT_READY until enough of the message has been processed by CryptMsgUpdate to make the CMSG_ENVELOPE_ALGORITHM_PARAM available. Once it is available, the application can then iterate through the recipients, retrieving the CERT_INFO for each using CryptMsgGetParam (CMSG_RECIPIENT_INFO_PARAM).

The CERT_INFO for a recipient is used to call CertGetSubjectCertificateFromStore to see if a matching certificate is in the "my" certificate store (CertOpenSystemStore or CertOpenStore must have been previously called to open the "my" store). When a match is found, CertGetCertificateContextProperty(CERT_KEY_PROV_INFO_PROP_ID) is called which returns a CRYPT_KEY_PROV_INFO structure that contains the information necessary to acquire the private key for that recipient. CryptAcquireContext is called using the pwszContainerName, pwszProvName, dwProvType, and dwFlags members of CRYPT_KEY_PROV_INFO as parameters to get the desired hCryptProv. This hCryptProv and the dwKeySpec from the CRYPT_KEY_PROV_INFO are passed to CryptMsgControl (as a member of the CMSG_CTRL_DECRYPT_PARA structure) to permit the start of the decryption of the inner content. The streaming code will then perform the decryption as the data is input, and the resulting blocks of plaintext gets passed to the callback specified by pfnStreamOutput where an application may save it to a file.

Note The streaming decode for an enveloped message queues up the ciphertext in memory until CryptMsgControl is called to start the decryption. It is up to the application to initiate decrypting in a timely manner so that the data can be saved to disk (or routed elsewhere) before the accumulated ciphertext becomes too large and the system runs out of memory.

Consider the case of a signed message enclosed in an enveloped message. The plaintext output from the streaming decode of the enveloped message can be fed into another streaming decode which can process the signed message.

Return Values

Returns a handle to the opened message if successful. Returns NULL if the operation failed.

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgClose, CryptMsgUpdate, CryptMsgGetParam, CryptMsgOpenToEncode


CryptMsgOpenToEncode

The CryptMsgOpenToEncode function opens a cryptographic message for encoding and returns a handle to the opened message. The message remains open until CryptMsgClose is called.

#include <wincrypt.h>
HCRYPTMSG WINAPI CryptMsgOpenToEncode(
  DWORD dwMsgEncodingType,         // in
  DWORD dwFlags,                   // in
  DWORD dwMsgType,                 // in
  const void *pvMsgEncodeInfo,     // in
  LPSTR pszInnerContentObjID,      // in/optional
  PCMSG_STREAM_INFO pStreamInfo    // in/optional
);

Parameters

dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwFlags
Flag values. Currently defined flags are shown in the following table:
Flag | Value
CMSG_BARE_CONTENT_FLAG | 0x00000001
CMSG_DETACHED_FLAG | 0x00000004
CMSG_AUTHENTICATED_ATTRIBUTES_FLAG | 0x00000008

CMSG_BARE_CONTENT_FLAG can be specified for a streamed message to indicate that the streamed output will not have an outer ContentInfo wrapper (as defined by PKCS #7). This makes it suitable to be streamed into an enclosing message.

The CMSG_DETACHED_FLAG indicates that there is detached data being supplied for the subsequent calls to CryptMsgUpdate.

The CMSG_AUTHENTICATED_ATTRIBUTES_FLAG indicates that authenticated attributes are forced to be included in the SignerInfo (as defined by PKCS #7) in cases where they would not otherwise be required.

dwMsgType
The message type. Currently defined types are shown in the following table.
Message type | Associated structures | Value
CMSG_DATA | Raw data (no associated structure) | 1
CMSG_SIGNED | CMSG_SIGNER_ENCODE_INFO, CMSG_SIGNED_ENCODE_INFO | 2
CMSG_ENVELOPED | CMSG_ENVELOPED_ENCODE_INFO | 3
CMSG_SIGNED_AND_
ENVELOPED 		Not implemented. 4
CMSG_HASHED | CMSG_HASHED_ENCODE_INFO | 5
CMSG_ENCRYPTED | Not implemented. | 6

CMSG_DATA. An octet (BYTE) string.

CMSG_SIGNED. Consists of content of any type and encrypted message digests of the content for zero or more signers.

CMSG_ENVELOPED. Consists of encrypted content of any type and encrypted content-encryption keys for one or more recipients. The combination of encrypted content and encrypted content-encryption key for a recipient is a digital envelope for that recipient. See Remarks for issues concerning changes made to the CryptoAPI which affect the handling of enveloped messages in order to support S/MIME e-mail interoperability.

CMSG_SIGNED_AND_ENVELOPED. Consists of encrypted content of any type, encrypted content-encryption keys for one or more recipients, and doubly encrypted message digests for one or more signers. The double encryption consists of an encryption with a signer's private key followed by an encryption with the content-encryption key.

CMSG_HASHED. Consists of content of any type and a message digest of the content.

Note Throughout the PKCS #7 specification, the terms "digest" and "digested" are used to refer to the value produced from applying a hashing algorithm to data. Throughout this document we have used the terms "hash" and "hashed" for the same purpose. For example, the data type used with the low-level message functions is called "hashed" rather than "digested." For the purposes of this document the two terms may be used interchangeably.

CMSG_ENCRYPTED. Consists of encrypted content of any type. Unlike the enveloped-data content type, the encrypted-data content type has neither recipients nor encrypted content-encryption keys. Keys are assumed to be managed by other means.

pvMsgEncodeInfo
Pointer to the data to be encoded. The type of data pointed to depends on the value of dwMsgType. The relationship between the dwMsgType and pvMsgEncodeInfo is given below:

When dwMsgType is CMSG_SIGNED, pvMsgEncodeInfo points to a CMSG_SIGNED_ENCODE_INFO structure which optionally contains an array of a CMSG_SIGNER_ENCODE_INFO structures.

When dwMsgType is CMSG_ENVELOPED, pvMsgEncodeInfo points to a CMSG_ENVELOPED_ENCODE_INFO structure.

When dwMsgType is CMSG_HASHED, pvMsgEncodeInfo points to a CMSG_HASHED_ENCODE_INFO structure.

pszInnerContentObjID
When calling CryptMsgOpenToEncode and the data that is to be provided to CryptMsgUpdate has already been message encoded, then the appropriate object identifier should be passed in pszInnerContentObjID (for example, "1.2.840.113549.1.7.2" for szOID_RSA_signedData). If pszInnerContentObjID is NULL, then the inner content type is assumed not to have been previously encoded, and is encoded as an octet string and given the type CMSG_DATA.

Note When streaming is being used, pszInnerContentObjID must be either NULL or szOID_RSA_data.

The following algorithm object identifiers are commonly used, and they can be found in Wincrypt.h. The user may also define his own inner content usage. All that is required in this case is for the sender and receiver of the message to agree upon the semantics associated with the object identifier.
Name | Base/Suffix | Value
szOID_RSA_data | szOID_PKCS_7 ".1" | "1.2.840.113549.1.7.1"
szOID_RSA_signedData | szOID_PKCS_7 ".2" | "1.2.840.113549.1.7.2"
szOID_RSA_envelopedData | szOID_PKCS_7 ".3" | "1.2.840.113549.1.7.3"
szOID_RSA_signEnvData | szOID_PKCS_7 ".4" | "1.2.840.113549.1.7.4"
szOID_RSA_digestedData | szOID_PKCS_7 ".5" | "1.2.840.113549.1.7.5"
szOID_RSA_encryptedData | szOID_PKCS_7 ".6" | "1.2.840.113549.1.7.6"
SPC_INDIRECT_DATA_OBJID | Not applicable | "1.3.6.1.4.1.311.2.1.4"

pStreamInfo
When streaming is not being used, this parameter should be set to NULL.

When streaming is being used, this parameter should point to a CMSG_STREAM_INFO structure. The callback specified by pfnStreamOutput in the CMSG_STREAM_INFO structure is called when CryptMsgUpdate is executed. The callback is passed the encoded bytes resulting from the encoding. For more information on how to use the callback, see CMSG_STREAM_INFO.

Consider the case of a signed message being enclosed in an enveloped message. The encoded output from the streaming encode of the signed message can be fed into another streaming encode of the enveloped message, for example, the callback for the streaming encode of the signed message calls CryptMsgUpdate for the encode of the enveloped message. The callback for the enveloped message receives the encoded bytes of the nested signed message.

Return Values

A handle to the opened message is returned if successful. Returns NULL if the operation failed.

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_OID_FORMAT | The object identifier is badly formatted.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | For dwMsgType == CMSG_SIGNED an error can be propagated from CryptCreateHash For dwMsgType == CMSG_ENVELOPED an error can be propagated from CryptGenKey CryptImportKey CryptExportKey For dwMsgType ==CMSG_HASHED an error can be propagated from CryptCreateHash

Remarks

Important changes have been made to the CryptoAPI which affects the handling of enveloped messages to support S/MIME e-mail interoperability. The changes take effect for products released after Service Pack 3, such as Microsoft® Internet Explorer 4.0 and Microsoft® Windows NT® 5.0. The following changes have been made:

For functions which perform encryption, the encrypted symmetric keys are reversed from little endian format to big endian format after CryptExportKey is called internally to the function. For functions which perform decryption, the encrypted symmetric keys are reversed from big endian format to little endian format before CryptImportKey is called internally to the function.

CRYPT_NO_SALT is specified when symmetric keys are generated and imported with CryptGenKey and CryptImportKey. Previously, 11 bytes of zero value salt was being used instead of using no salt.

For messages encrypted with the RC2 encryption algorithm, the KP_EFFECTIVE_KEYLEN is used with CryptGetKeyParam to determine the effective key length of the RC2 key being imported/exported (40, 64, or 128 bits). Previously, a default key length of 40 bits was always used when importing/exporting keys.

For messages encrypted with the RC2 encryption algorithm, encode and decode operations have been updated to handle ASN RC2 parameters for the contentEncryptionAlgorithm specified in the CMSG_ENVELOPED_ENCODE_INFO. Previously, the parameters were not supported. See the S/MIME documentation for more information.

For messages encrypted with the RC4, DES, and 3DES encryption algorithms, encode and decode operations have been updated to handle the ASN IV octet string parameter for the contentEncryptionAlgorithm specified in the CMSG_ENVELOPED_ENCODE_INFO. Previously, that parameter was not supported. See the S/MIME documentation for more information.

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgClose, CryptMsgUpdate, CryptMsgGetParam, CryptMsgOpenToDecode


CryptMsgSignCTL

The CryptMsgSignCTL function creates a signed message containing the encoded CTL.

#include <wincrypt.h>
BOOL WINAPI CryptMsgSignCTL(
  DWORD dwMsgEncodingType,             // in
  BYTE *pbCtlContent,                  // in
  DWORD cbCtlContent,                  // in
  PCMSG_SIGNED_ENCODE_INFO pSignInfo,  // in
  DWORD dwFlags,                       // in
  BYTE *pbEncoded,                     // out
  DWORD *pcbEncoded                    // in/out
);

Parameters

dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbCtlContent
The encoded CTL_INFO which may be obtained via a CTL_CONTEXT's pbCtlContent member or via a CryptEncodeObject (PKCS_CTL).
cbCtlContent
The count, in bytes, of the content pointed to by pbCtlContent.
pSignInfo
Points to a CMSG_SIGNED_ENCODE_INFO structure which optionally contains an array of a CMSG_SIGNER_ENCODE_INFO structures.

The message can be encoded without any signers if the CMSG_SIGNED_ENCODE_INFO structure's cbSize member is set to the size of the structure and all of the other members are set to zero.

dwFlags
Flag values. This parameter is reserved for future use and should be set to zero in the interim.
pbEncoded
Pointer to a buffer that receives the encoded message produced.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbEncoded
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbEncoded parameter. When the function returns, the variable pointed to by the pcbEncoded parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pbEncoded is NULL.

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
Propagated errors that may be encountered: | An error can be propagated from CryptMsgOpenToEncode CryptMsgUpdate

Example

// EXAMPLE CODE FOR USING CryptMsgSignCTL().
// Creates a signed message.
// Assume that pointers to the CTL_INFO structure
// (pbCtlContent), and the PCMSG_SIGNED_ENCODE_INFO
// (pSignInfo) have already been defined.

// Set up the variables.
DWORD dwMsgEncodingType = CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING;
                                   // Type of encoding
BYTE *pbCtlContent;                // Pointer to the encoded CTL_INFO
DWORD cbCtlContent = 128;          // # of bytes of CTL_INFO
PCMSG_SIGNED_ENCODE_INFO pSignInfo;// Pointer to
                                   //   CMSG_SIGNED_ENCODE_INFO
                                   //   structure
DWORD dwFlags = 0;                 // Flag values- reserved- set to 0
BYTE *pbEncoded;                   // out
DWORD cbEncoded;                   // in/out
BOOL fResult;                      // Return TRUE if function succeeds
                                   //   FALSE if function fails

// Function called the first time to get a pointer to
// the size of the encoded message (cbEncoded)
fResult= CryptMsgSignCTL(
           dwMsgEncodingType,
           pbCtlContent,
           cbCtlContent,
           pSignInfo,
           0,                      // dwFlags set to 0
           NULL,                   // NULL on first call
           &cbEncoded);

if (!fResult){
  cout << "first call to CryptMsgSignCTL failed"<< endl;
}
else {
  cout<< "first call to CryptMsgSignCTL successful"<< endl;
  pbEncoded = (BYTE*) malloc (cbEncoded);
  cout<< "memory allocated"<< endl;
}
// Function call to a pointer to the encoded message
fResult= CryptMsgSignCTL(
           dwMsgEncodingType,      // in
           pbCtlContent,           // in
           cbCtlContent,           // in
           pSignInfo,              // in
           dwFlags,                // in
           pbEncoded,              // out
           &cbEncoded);            // in/out

if (!fResult) {                    // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                             // TRUE
 cout<< "Function succeeded"<< endl
     << "size = "<< &cbEncoded<< endl
     << "encoded message at location = "<< pbEncoded<< endl;
}
free (pbEncoded);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CMSG_SIGNED_ENCODE_INFO, CryptMsgEncodeAndSignCTL, CryptMsgOpenToEncode


CryptMsgUpdate

The CryptMsgUpdate function updates the contents of a cryptographic message, thereby allowing messages to be constructed piecemeal, by repetitively calling CryptMsgUpdate. Depending on how the message was opened, the content is either encoded or decoded.

#include <wincrypt.h>
BOOL WINAPI CryptMsgUpdate(
  HCRYPTMSG hCryptMsg,    // in
  const BYTE *pbData,     // in
  DWORD cbData,           // in
  BOOL fFinal             // in
);

Parameters

hCryptMsg
A handle to a cryptographic message.
pbData
A pointer to the buffer holding the data that is to be encoded or decoded.
cbData
The number of bytes of data pointed to by pbData.
fFinal
Used to indicate when the last block of data for an encode or decode is being processed. Correct usage of this flag is dependent upon whether the message being processed has detached data.

When there is no detached data (the CMSG_DETACHED_FLAG flag was not used) and a message has been opened (either CryptMsgOpenToDecode or CryptMsgOpenToEncode was performed for the message), fFinal should be set to true, and CryptMsgUpdate is only called once.

When there is detached data (the CMSG_DETACHED_FLAG flag was used) and a message has been opened for encode (CryptMsgOpenToEncode was performed for the message), fFinal should be set to true only on the last call to CryptMsgUpdate.

For detached data in the decode case, the header and the content of a message are contained in different blobs. Each blob requires that fFinal be set to true as described below.

When there is detached data (the CMSG_DETACHED_FLAG flag was used) and a message has been opened for decode (CryptMsgOpenToDecode was performed for the message), fFinal should be set to true when the header is processed by a single call to CryptMsgUpdate. Then fFinal is set false while processing the detached data in subsequent calls to CryptMsgUpdate, until the last detached data block is to be processed, where it should be set true again.

Return Values

If the function fails, the return value is false (zero). If it succeeds, the return value is true (non-zero).

To retrieve extended error information, use the GetLastError function.

Errors encountered in the application defined callback function specified by pStreamInfo in CryptMsgOpenToDecode and CryptMsgOpenToEncode may be propagated to CryptMsgUpdate if streaming is used. If this happens, SetLastError is not called by CryptMsgUpdate after the callback returns, which preserves any errors encountered under the control of the application. It is the responsibility of the callback function (or one of the APIs that it calls) to call SetLastError if an error occurs while the application is processing the streamed data.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_INVALID_MSG_TYPE | The message type is invalid.
CRYPT_E_MSG_ERROR | An error was encountered doing a cryptographic operation.
CRYPT_E_OID_FORMAT | The object identifier is badly formatted.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_ENCODING | The message is not encoded as expected.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered when a message has been opened for encode: | When the message type is CMSG_SIGNED CryptHashData CryptGetHashParam CryptSignHash When the message type is CMSG_ENVELOPED CryptGetKeyParam CryptEncrypt When the message type is CMSG_HASHED CryptHashData CryptGetHashParam
Propagated errors that may be encountered when a message has been opened for decode: | When the message type is CMSG_SIGNED CryptCreateHash CryptHashData When the message type is CMSG_HASHED CryptCreateHash CryptHashData

Example

See Signed Message Example Code.

See Enveloped Message Example 1.

See Hashed Message Example Code.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgGetParam, CryptMsgOpenToEncode, CryptMsgOpenToDecode


CryptMsgVerifyCountersignatureEncoded

The CryptMsgVerifyCountersignatureEncoded function verifies a countersignature in terms of the SignerInfo data structure (as defined by PKCS # 7); that is, verify that pbSignerInfoCountersignature contains the encrypted hash of the encryptedDigest field of pbSignerInfo.

#include <wincrypt.h>
BOOL WINAPI CryptMsgVerifyCountersignatureEncoded(
  HCRYPTPROV hCryptProv,                 // in
  DWORD dwMsgAndCertEncodingType,        // in
  PBYTE pbSignerInfo,                    // in
  DWORD cbSignerInfo,                    // in
  PBYTE pbSignerInfoCountersignature,    // in
  DWORD cbSignerInfoCountersignature,    // in
  PCERT_INFO pciCountersigner            // in
);

Parameters

hCryptProv
Specifies a handle to the cryptographic provider to use to hash the encryptedDigest field of pbSignerInfo.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation, as shown in the following example:
CRYPT_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
CRYPT_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbSignerInfo
A pointer to the encoded blob which contains the signer of the contents of a message that is to be countersigned.
cbSignerInfo
The count, in bytes, of the encoded blob for the signer of the contents.
pbSignerInfoCountersignature
A pointer to the encoded blob that contains the countersigner information.
cbSignerInfoCountersignature
The count, in bytes, of the encoded blob for the countersigner of the message.
pciCountersigner
Contains an encoded blob with the issuer and serial number of the counter signer. See "Remarks".

Return Values

If the function fails, the return value is FALSE (zero). If it succeeds, the return value is TRUE (non-zero).

To retrieve extended error information, use the GetLastError function.

The following table lists the error codes most commonly returned by the GetLastError function.

Error code | Description
CRYPT_E_AUTH_ATTR_MISSING | The message does not contain an expected authenticated attribute.
CRYPT_E_HASH_VALUE | The hash value is not correct.
CRYPT_E_ISSUER_SERIALNUMBER | The issuer and/or serial number is not valid.
CRYPT_E_OSS_ERROR | OSS Certificate encode/decode error code base. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_ENCODING | The message is not encoded as expected.
CRYPT_E_UNKNOWN_ALGO | The cryptographic algorithm is unknown.
E_INVALIDARG | One or more arguments are invalid.
E_OUTOFMEMORY | Ran out of memory.
Propagated errors that may be encountered: | An error can be propagated from: CryptCreateHash CryptHashData CryptGetHashParam CryptImportKey CryptVerifySignature

Remarks

The issuer and serial number of the counter signer must match with the countersigner information from pbSignerInfoCountersignature. The only fields referenced from pciCountersigner are SerialNumber, Issuer, and SubjectPublicKeyInfo. The SubjectPublicKeyInfo is used to import the public key, which is then used to perform a cryptographic operation on the hash from the pciCountersigner, which is compared with the hash that is computed from the pbSignerInfo.

Example

See Example Code For Countersigning a Message.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptMsgCountersign, CryptMsgCountersignEncoded


Simplified Message Functions

These are Win32® functions that wrap several of the lower-level Microsoft® CryptoAPI functions into a single function to accomplish a given task. This makes it easier for you to accomplish those specific tasks.

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CryptDecodeMessage | Decodes a cryptographic message.
CryptDecryptAndVerifyMessageSignature | Decrypts the specified message and verifies the signer.
CryptDecryptMessage | Decrypts the specified message.
CryptEncryptMessage | Encrypts the message for the recipient or recipients.
CryptGetMessageCertificates | Returns the certificate store containing the message's certificates and CRLs.
CryptGetMessageSignerCount | Returns the count of signers in the signed message.
CryptHashMessage | Creates a hash of the message.
CryptSignAndEncryptMessage | Signs the message and encrypts for the recipient or recipients.
CryptSignMessage | Signs the message.
CryptVerifyDetachedMessageHash | Verifies a hashed message containing a detached hash.
CryptVerifyDetachedMessageSignature | Verifies a signed message containing a detached signature or signatures.
CryptVerifyMessageHash | Verifies a hashed message.
CryptVerifyMessageSignature | Verifies a signed message.


CryptDecodeMessage

The CryptDecodeMessage function decodes, decrypts, and verifies a cryptographic message.

This function may be used when the type of cryptographic message is unknown. The constants for dwMsgTypeFlags may be combined with a bitwise OR operation so that the function will try to find one of the types. When one of the types is found, the function will report the type found, and return the data appropriate for the type found (see the pbDecoded parameter).

In a single pass, the function cracks only the first level of encryption or encoding. For additional cracking, the function needs to be called again, or one of the other Simplified Message Functions used for the additional cracking must be called.

#include <wincrypt.h>
BOOL WINAPI CryptDecodeMessage(
  DWORD dwMsgTypeFlags,                       // in
  PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara,   // in
  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,     // in
  DWORD dwSignerIndex,                        // in
  const BYTE *pbEncodedBlob,                  // in
  DWORD cbEncodedBlob,                        // in
  DWORD dwPrevInnerContentType,               // in
  DWORD *pdwMsgType,                          // out/optional
  DWORD *pdwInnerContentType,                 // out/optional
  BYTE *pbDecoded,                            // out/optional
  DWORD *pcbDecoded,                          // in/out/optional
  PCCERT_CONTEXT *ppXchgCert,                 // out/optional
  PCCERT_CONTEXT *ppSignerCert                // out/optional
);

Parameters

dwMsgTypeFlags
Flags that control what message types get decoded. The following types are defined, and may be combined with the bitwise OR operator:
  • CMSG_DATA_FLAG
  • CMSG_SIGNED_FLAG
  • CMSG_ENVELOPED_FLAG
  • CMSG_SIGNED_AND_ENVELOPED_FLAG
  • CMSG_HASHED_FLAG
pDecryptPara
Pointer to the decryption parameters. For details, see Simplified Message Data Structures. Applicable to the message types: CMSG_ENVELOPED or CMSG_SIGNED_AND_ENVELOPED.
pVerifyPara
Pointer to the verification parameters. For details, see Simplified Message Data Structures. Applicable to the message types: CMSG_SIGNED, CMSG_SIGNED_AND_ENVELOPED and CMSG_HASHED.
dwSignerIndex
Message might have more than one signer, so dwSignerIndex is an index to a particular signer, and can be iterated with multiple calls to the function. It should be set to zero for the first signer, or, as is the usual case, for a single signer. If the function returns FALSE, and GetLastError returns CRYPT_E_NO_SIGNER, the previous call got the last signer of the message. Only applicable to the message types: CMSG_SIGNED_AND_ENVELOPED or CMSG_SIGNED.
pbEncodedBlob
Pointer to the encoded blob that is to be decoded.
cbEncodedBlob
The size, in bytes, of the encoded blob.
dwPrevInnerContentType
Only applicable when processing nested cryptographic messages. When processing an outer cryptographic message, it must be set to zero. When decoding a nested cryptographic message, it should be set to the value returned at pdwInnerContentType by a previous calling of CryptDecodeMessage for the outer message. It can be any of the CMSG types listed in pdwMsgType. Set to zero for backward compatibility.
pdwMsgType
An optional parameter. Specifies the address where the message type is returned. Possible message types are:

CMSG_DATA
CMSG_SIGNED
CMSG_ENVELOPED
CMSG_SIGNED_AND_ENVELOPED
CMSG_HASHED

pdwInnerContentType
An optional parameter that is updated with the type of the inner message. Unless there is cryptographic message nesting, CMSG_DATA is returned. Set to NULL for backward compatibility.
pbDecoded
Optional parameter. Pointer to a buffer that receives the decoded message.

This parameter can be NULL if the decoded message is not required, or to set the size of the decoded message for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbDecoded
An optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbDecoded parameter. When the function returns, this variable contains the size of the decoded message copied to *pbDecoded. A decoded message will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

ppXchgCert
An optional parameter. It's a pointer to the certificate context pointer corresponding to the exchange (private) key used to decode the message. Only updated for CMSG_ENVELOPED or CMSG_SIGNED_AND_ENVELOPED.
ppSignerCert
An optional parameter. It is a pointer to the certificate context pointer of the signer. Only updated for CMSG_SIGNED or CMSG_SIGNED_AND_ENVELOPED.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptDecryptMessage, CryptVerifyMessageSignature, or CryptVerifyMessageHash may be propagated to this function.

This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbDecoded parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbDecoded.

Remarks

The dwMsgTypeFlags parameter specifies the set of allowable messages. For example, to decode either SIGNED or ENVELOPED messages, set dwMsgTypeFlags to CMSG_SIGNED_FLAG | CMSG_ENVELOPED_FLAG. Either or both of the pDecryptPara or pVerifyPara parameters must be specified.

Note that *pdwMsgType is updated with the type of the message.

For a successfully decoded or verified message, the certificate context pointers pointed to by ppXchgCert and ppSignerCert are updated. They must be freed by calling CertFreeCertificateContext. If the function fails, they are set to NULL.

ppXchgCert or ppSignerCert can be NULL, indicating the caller isn't interested in getting the exchange certificate or the signer certificate context.

Example

// EXAMPLE CODE FOR USING CryptDecodeMessage().
// Decodes, decrypts, and verifies a cryptographic message.
// Assume that pointers to the decription paramaters
// (pDecryptPara), the verification paramaters (pVerifyPara),
// and the encoded blob (pbEncodedBlob) have already been defined.

// Set up the variables.
DWORD dwMsgTypeFlags = CMSG_DATA_FLAG | CMSG_SIGNED_FLAG;
                                  // Type of message flag
PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara;
                                  // Struct initialized elsewhere -
                                  //   Pointer to decryption
                                  //   paramaters
PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara;
                                  // Struct initialized elsewhere -
                                  //   Pointer to verification
                                  //   paramaters
DWORD dwSignerIndex = 0;          // Signer index -  0 for the first
                                  //   signer
const BYTE *pbEncodedBlob;        // Initialized elsewhere -
                                  //   Pointer to the encoded blob
DWORD cbEncodedBlob = 128;        // Size of encoded blob
DWORD dwPrevInnerContentType = 0; // Previous content type (eg.
                                  //   CMSG_DATA) - set to 0 for outer
                                  //   nested messages
DWORD *pdwMsgType;                // Pointer to the message type
DWORD *pdwInnerContentType;       // Pointer to type of inner message
                                  //   for outer message set to NULL
BYTE *pbDecoded;                  // Pointer to decoded message buffer
DWORD cbDecoded;                  // Size of decoded message
PCCERT_CONTEXT *ppXchgCert;       // Pointer to certificate context
                                  //   pointer of the exchange key
PCCERT_CONTEXT *ppSignerCert;     // Pointer to certificate context
                                  //   pointer of the signer
BOOL fResult;                     // Return TRUE if function succeeds
                                  //   FALSE if function fails

// Function called the first time to get the
// size of the decoded message (cbDecoded)
fResult= CryptDecodeMessage(
           dwMsgTypeFlags,
           pDecryptPara,
           pVerifyPara,
           dwSignerIndex,
           pbEncodedBlob,
           cbEncodedBlob,
           dwPrevInnerContentType,
           pdwMsgType,
           pdwInnerContentType,
           NULL,                        // NULL on first call
           &cbDecoded,
           ppXchgCert,
           ppSignerCert);

if (!fResult){
  cout<< "first call to CryptDecodeMessage failed"<< endl;
}
else {
  cout<< "first call to CryptDecodeMessage successful"<< endl;
  pbDecoded = (BYTE*) malloc (cbDecoded);
  cout<< "memory allocated"<< endl;
}

// Function call decode the first level of encryption
fResult= CryptDecodeMessage(
           dwMsgTypeFlags,              // in
           pDecryptPara,                // in
           pVerifyPara,                 // in
           dwSignerIndex,               // in
           pbEncodedBlob,               // in
           cbEncodedBlob,               // in
           dwPrevInnerContentType,      // in
           pdwMsgType,                  // out/optional
           pdwInnerContentType,         // out/optional
           pbDecoded,                   // out/optional
           &cbDecoded,                  // in/out/optional
           ppXchgCert,                  // out/optional
           ppSignerCert);               // out/optional

if (!fResult) {                         // FALSE
 cout<< "Function failed"<< endl
     << "error code = "<< GetLastError()<< endl;
}
else {                                  // TRUE
  cout<< "Function succeeded"<< endl
      << "message type = "<< &pdwMsgType<< endl
      << "inner message type (NULL) = "<< &pdwInnerContentType<< endl
      << "size = "<< cbDecoded<< endl
      << "located at = "<< pbDecoded<< endl;
}
free (pbDecoded);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptDecryptMessage, CryptVerifyMessageHash, CryptVerifyMessageSignature


CryptDecryptAndVerifyMessageSignature

The CryptDecryptAndVerifyMessageSignature function decrypts the message and verifies the signer.

#include <wincrypt.h>
BOOL WINAPI CryptDecryptAndVerifyMessageSignature(
  PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara,      // in
  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,        // in
  DWORD dwSignerIndex,                           // in
  const BYTE *pbEncryptedBlob,                   // in
  DWORD cbEncryptedBlob,                         // in
  BYTE *pbDecrypted,                             // out, optional
  DWORD *pcbDecrypted,                           // in/out, optional
  PCCERT_CONTEXT *ppXchgCert,                    // out, optional
  PCCERT_CONTEXT *ppSignerCert                   // out, optional
);

Parameters

pDecryptPara
Pointer to the decryption parameters. For details, see Simplified Message Data Structures.
pVerifyPara
Pointer to the verification parameters. For details, see Simplified Message Data Structures.
dwSignerIndex
A message might have more than one signer. dwSignerIndex is an index to a particular signer, and can be iterated with multiple calls to the function. It should be set to zero for the first signer, or, as is the usual case, for a single signer. If the function returns FALSE, and GetLastError returns CRYPT_E_NO_SIGNER, the previous call got the last signer of the message.
pbEncryptedBlob
Pointer to the signed, encoded, and encrypted message that is to be decrypted and verified.
cbEncryptedBlob
Size, in bytes, of the encrypted message.
pbDecrypted
An optional parameter. Pointer to a buffer that receives the decrypted message.

This parameter can be NULL if the decrypted message is not required, or to set the size of the decrypted message for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbDecrypted
An optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbDecrypted parameter. When the function returns, this variable contains the size of the decrypted message copied to *pbDecrypted. A decrypted message will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

ppXchgCert
An optional parameter. It is a pointer to the certificate context pointer corresponding to the exchange (private) key used to decrypt the message.
ppSignerCert
An optional parameter. It is a pointer to the certificate context pointer of the signer.

Return Values

TRUE if the function succeeded—the message was decrypted and the signer was verified. FALSE if the signer was not verified or if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptDecryptMessage and CryptVerifyMessageSignature may be propagated to this function.

This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbDecrypted parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbDecrypted.

Remarks

For a successfully decrypted and verified message, the certificate context pointers pointed to by ppXchgCert and ppSignerCert are updated. They must be freed by calling CertFreeCertificateContext. If the function fails, they are set to NULL.

ppXchgCert and/or ppSignerCert can be NULL, indicating the caller isn't interested in getting the exchange certificate or the signer certificate context.

Example

// EXAMPLE CODE FOR USING CryptDecryptAndVerifyMessageSignature() to
// decrypt a message and verify the signer(s). In this example, the
// caller is not interested in getting the certificate contexts,
// and therefore sets ppXchgCert and ppSignerCert to NULL.

// Assume that the application has a pointer (pbEncryptedBlob) to
// the received message string, and its size (cbEncryptedBlob).

// Set up the variables.
CRYPT_DECRYPT_MESSAGE_PARA  DecryptPara;  //Struct initialized
                                          //   elsewhere
CRYPT_VERIFY_MESSAGE_PARA   VerifyPara;   //Struct initialized
                                          //   elsewhere
DWORD                       dwSignerIndex = 0;
DWORD                       cbDecrypted;

// Call CryptDecryptAndVerifyMessageSignature() to verify the signers.
BOOL        fReturn =            FALSE;
DWORD       dwReturn;
BOOL        fSignersVerified =   FALSE;

while(TRUE)
{

    fReturn = CryptDecryptAndVerifyMessageSignature(&DecryptPara,
              &VerifyPara, dwSignerIndex, pbEncryptedBlob,
              cbEncryptedBlob,    NULL, NULL, NULL, NULL);
    if(fReturn != TRUE)    // Function call failed.
    {
        dwReturn = GetLastError();

        if (dwReturn == CRYPT_E_NO_SIGNER)
        {
            fSignersVerified = TRUE;
            break;
        }
        else
        {
            // A signer was not verified or an error occurred.
            // Handle the condition.
        }
    }
    dwSignerIndex ++;
}

// If fSignersVerified = TRUE at this point all signers were
// verified.

// Call CryptDecryptAndVerifyMessageSignature() to get the size of the
// decrypted message.
fReturn =    FALSE;
dwSignerIndex = 0;

fReturn = CryptDecryptAndVerifyMessageSignature(&DecryptPara,
          &VerifyPara, dwSignerIndex, pbEncryptedBlob,
          cbEncryptedBlob, NULL, &cbDecrypted, NULL, NULL);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the call succeeded, the size of the message, in bytes,
// now resides in cbDecrypted.

// Malloc memory for the size of the message.
BYTE* pbDecrypted;

pbDecrypted = (BYTE*)malloc(cbDecrypted);
if(pbDecrypted == NULL)
    ;// Handle the memory allocation error.

// Call CryptDecryptAndVerifyMessageSignature() again to decrypt
// and return the message.
fReturn = CryptDecryptAndVerifyMessageSignature(&DecryptPara,
          &VerifyPara, dwSignerIndex, pbEncryptedBlob,
          cbEncryptedBlob, pbDecrypted, &cbDecrypted, NULL, NULL);
if(fReturn != TRUE)
    ;// The function call failed.  Handle the error.

// If the function succeeded, the decrypted message is now
// at the location pointed to by pbDecrypted.

// Perform local processing on the message.
...

// Free memory.
free (pbDecrypted);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptDecryptMessage


CryptDecryptMessage

The CryptDecryptMessage function decodes and decrypts a message.

#include <wincrypt.h>
BOOL WINAPI CryptDecryptMessage(
  PCRYPT_DECRYPT_MESSAGE_PARA pDecryptPara, // in
  const BYTE *pbEncryptedBlob,              // in
  DWORD cbEncryptedBlob,                    // in
  BYTE *pbDecrypted,                        // out, optional
  DWORD *pcbDecrypted,                      // in/out, optional
  PCCERT_CONTEXT *ppXchgCert                // out, optional
);

Parameters

pDecryptPara
Pointer to the decryption parameters. For details, see Simplified Message Data Structures.
pbEncryptedBlob
Pointer to the encoded and encrypted message that is to be decrypted.
cbEncryptedBlob
Size of the encoded and encrypted message, in bytes.
pbDecrypted
Optional parameter. Pointer to a buffer that receives the decrypted message.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbDecrypted
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbDecrypted parameter. When the function returns, this variable contains the size, in bytes, of the decrypted message copied to *pbDecrypted. A decrypted message will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

ppXchgCert
Optional parameter. It's a pointer to the certificate context pointer corresponding to the exchange (private) key used to decrypt the message.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptImportKey and CryptDecrypt may be propagated to this function. This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbDecrypted parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbDecrypted.
E_INVALIDARG | Invalid message and certificate encoding types. Currently only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING_TYPE are supported. Invalid cbSize in *pDecryptPara.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_MSG_TYPE | Not an enveloped cryptographic message.
NTE_BAD_ALGID | The message was encrypted using an algorithm we don't know about or support.
CRYPT_E_NO_DECRYPT_CERT | No certificate was found having a private key property to use for decrypting.

Remarks

Notice that when NULL is passed for pbDecrypted, and pcbDecrypted isn't NULL, then NULL is returned for the address passed in ppXchgCert. Otherwise, a pointer to the certificate context pointer is returned. For a successfully decrypted message, the information contained at *ppXchgCert is updated with the pointer to the certificate context used to decrypt. It must be freed by calling CertFreeCertificateContext. If the function fails, the value at ppXchgCert is set to NULL. Also, NULL can be initially passed for ppXchgCert, indicating the caller isn't interested in getting the certificate context used to decrypt.

Example

See Example Code Using CryptDecryptMessage.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptDecryptAndVerifyMessageSignature


CryptEncryptMessage

The CryptEncryptMessage function encrypts and encodes a message.

#include <wincrypt.h>
BOOL WINAPI CryptEncryptMessage(
  PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara, // in
  DWORD cRecipientCert,                     // in
  PCCERT_CONTEXT rgpRecipientCert[ ],       // in
  const BYTE *pbToBeEncrypted,              // in
  DWORD cbToBeEncrypted,                    // in
  BYTE *pbEncryptedBlob,                    // out
  DWORD *pcbEncryptedBlob                   // in/out
);

Parameters

pEncryptPara
Pointer to the encryption parameters. For details, see Simplified Message Data Structures.
cRecipientCert
Number of elements in the rgpRecipientCert[] array.
rgpRecipientCert[]
Array of pointers to certificate contexts for the intended recipients of the message.
pbToBeEncrypted
Pointer to an application's content (message) that is to be encrypted.
cbToBeEncrypted
Size, in bytes, of the message that is to be encrypted.
pbEncryptedBlob
Pointer to a buffer that receives the encrypted and encoded message.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbEncryptedBlob
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbEncryptedBlob parameter. When the function returns, this variable contains the size, in bytes, of the encrypted and encoded message copied to *pbEncryptedBlob.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptGenKey, CryptEncrypt, CryptImportKey, and CryptExportKey may be propagated to this function. This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbEncryptedBlob parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbEncryptedBlob.
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported. Invalid cbSize in *pEncryptPara.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Example

See Example Code Using CryptEncryptMessage.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.


CryptGetMessageCertificates

The CryptGetMessageCertificates function returns the certificate store containing the message's certificates and CRLs. This function calls CertOpenStore using provider type CERT_STORE_PROV_PKCS7 for lpszStoreProvider. See CertOpenStore for additional details.

#include <wincrypt.h>
HCERTSTORE WINAPI CryptGetMessageCertificates(
  DWORD dwMsgAndCertEncodingType,  // in
  HCRYPTPROV hCryptProv,           // in
  DWORD dwFlags,                   // in
  const BYTE *pbSignedBlob,        // in
  DWORD cbSignedBlob               // in
);

Parameters

dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

hCryptProv
Specifies a handle to the cryptographic provider passed to CertOpenStore. See CertOpenStore for additional details.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

dwFlags
The flags passed to CertOpenStore. See CertOpenStore for additional details.
pbSignedBlob
A pointer to the signed message.
cbSignedBlob
The size, in bytes, of the signed message.

Return Values

Returns the certificate store containing the message's certificates and CRLs. For an error, NULL is returned.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
E_INVALIDARG | Invalid message and certificate encoding types. Currently only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING are supported.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Remarks

Use GetLastError to determine the reason for any errors.

Example

// EXAMPLE CODE FOR USING CryptGetMessageCertificates().
// Gets the certificate store with the message's certificates and CRLs.
// Assume that a pointer to the signed message
// (pbSignedBlob) has already been defined.

// Set up the variables.
DWORD dwMsgAndCertEncodingType =X509_ASN_ENCODING|PKCS_7_ASN_ENCODING;
                            // Type of encoding
HCRYPTPROV hCryptProv = 0;  // Service Provider handle
DWORD dwFlags = CERT_STORE_NO_CRYPT_RELEASE_FLAG;
                            // Flags to CertOpenStore
const BYTE *pbSignedBlob;   // Initialized elsewhere -
                            //   Pointer to the signed message
DWORD cbSignedBlob = 128;   // Size of message
HCERTSTORE hResult;         // Returns a certificate store

// Function call to receive the certificate store
hResult= CryptGetMessageCertificates(
           dwMsgAndCertEncodingType,  // in
           hCryptProv,                // in
           dwFlags,                   // in
           pbSignedBlob,              // in
           cbSignedBlob);             // in

if (hResult == NULL) {                // FALSE
  cout<< "Function failed"<< endl
      << "error code = "<< GetLastError()<< endl;
}
else {                                // TRUE
  cout<< "Function succeeded"<< endl;
}

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyMessageSignature


CryptGetMessageSignerCount

The CryptGetMessageSignerCount function returns the count of signers in the signed message.

#include <wincrypt.h>
LONG WINAPI CryptGetMessageSignerCount(
  DWORD dwMsgEncodingType,    // in
  const BYTE pbSignedBlob,    // in
  DWORD *cbSignedBlob         // in
);

Parameters

dwMsgEncodingType
The type of encoding used on the message. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation, as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbSignedBlob
A pointer to the signed message.
cbSignedBlob
The size, in bytes, of the signed message.

Return Values

Returns the count of signers in the signed message. Returns a zero when there are no signers. Returns a minus one for an error, and updates LastError accordingly.

Call GetLastError to see the reason for any failures. This function has the following error codes.

Error code | Description
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Remarks

Use GetLastError to determine the reason for any errors.

Example

//-------------------------------------------------------------------
// CryptGetMessageSignerCount() - Getting the number of signers of
// a message.
//-------------------------------------------------------------------

// Assume that the application has a pointer (pbSignedBlob) to
// the signed message, and its size (cbSignedBlob).

DWORD dwMsgEncodingType = PKCS_7_ASN_ENCODING;
BYTE* pbSignedBlob;      // Initialized elsewhere
DWORD cbSignedBlob;      // Initialized elsewhere
LONG  lSignerCount = 0;
DWORD dwLastError = 0;

lSignerCount = CryptGetMessageSignerCount(
                dwMsgEncodingType,
                pbSignedBlob,
                cbSignedBlob);
if(lSignerCount < 0)
    dwLastError = GetLastError();
    // handle the error

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyMessageSignature


CryptHashMessage

The CryptHashMessage function creates a hash of the message.

#include <wincrypt.h>
BOOL WINAPI CryptHashMessage(
  PCRYPT_HASH_MESSAGE_PARA pHashPara, // in
  BOOL fDetachedHash,                 // in
  DWORD cToBeHashed,                  // in
  const BYTE *rgpbToBeHashed[ ],      // in
  DWORD rgcbToBeHashed[ ],            // in
  BYTE *pbHashedBlob,                 // out, optional
  DWORD *pcbHashedBlob,               // in/out, optional
  BYTE *pbComputedHash,               // out, optional
  DWORD *pcbComputedHash              // in/out, optional
);

Parameters

pHashPara
Pointer to the hash parameters. For details, see Simplified Message Data Structures.
fDetachedHash
If this parameter is set to TRUE, only pbComputedHash is encoded in pbHashedBlob. Otherwise, both rgpbToBeHashed and pbComputedHash are encoded.
cToBeHashed
Number of array elements in rgpbToBeHashed[] and rgcbToBeHashed[]. This parameter can only be one (1) unless fDetachedHash is set to TRUE.
rgpbToBeHashed[]
Array of pointers that point to the contents to be hashed.
rgcbToBeHashed[]
Array of sizes, in bytes, for the contents pointed to by rgpbToBeHashed[].
pbHashedBlob
Optional parameter. Pointer to a buffer that receives the hashed message (the hash, and if fDetachedHash is TRUE, the content that was hashed, which has been encoded for transmission).

This parameter can be NULL if the hashed message is not needed for additional processing, or to set the size of the hashed message for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbHashedBlob
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbHashedBlob parameter. When the function returns, this variable contains the size, in bytes, of the decrypted message copied to *pbHashedBlob. A hashed message will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

pbComputedHash
Optional parameter. Pointer to a buffer that receives only the newly created, unencoded hash. This parameter can be NULL if the newly created hash is not needed for additional processing, or to set the size of the hash for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.
pcbComputedHash
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, this variable contains the size, in bytes, of the newly created hash that was copied to *pbComputedHash. A computed hash will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, and CryptGetHashParam may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported. Invalid cbSize in *pHashPara.
ERROR_MORE_DATA | If the buffer specified by the pbHashedBlob parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbHashedBlob.

Example

// EXAMPLE CODE FOR USING CryptHashMessage() to hash a single
// message.
// The hash is not to be detached, and the computed hash is not
// to be returned.

// Assume that the application already knows the address of the
// message array (rgpbToBeHashed[]) and the size of each element
// of that array (rgcbToBeHashed[]).

// Set up the variables.
CRYPT_HASH_MESSAGE_PARA      HashPara; // Struct initialized elsewhere
const BYTE*                  rgpbToBeHashed[1];
DWORD                        rgcbToBeHashed[1];
DWORD                        cbHashedBlob;

// Call CryptHashMessage() to get the size of the hashed and encoded message.
BOOL        fReturn =            FALSE;

fReturn = CryptHashMessage(&HashPara, FALSE, 1, rgpbToBeHashed,
          rgcbToBeHashed, NULL, &cbHashedBlob,
          NULL, NULL);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the call succeeded, the size of the message, in bytes,
// now resides in cbHashedBlob.

// Malloc memory for the size of the message.
BYTE* pbHashedBlob;

pbHashedBlob = (BYTE*)malloc(cbHashedBlob);
if(pbHashedBlob = NULL)
    ;// Handle the memory allocation error.

// Call CryptHashMessage to return the hashed and encoded message.

fReturn = CryptHashMessage(&HashPara, FALSE, 1, rgpbToBeHashed,
          rgcbToBeHashed, pbHashedBlob,
          &cbHashedBlob, NULL, NULL);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the function succeeded, the hash and encoded message are now
// at the location pointed to by pbHashedBlob.

// Perform local processing on the message.
...

// Free memory.
free (pbHashedBlob);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyDetachedMessageHash, CryptVerifyMessageHash


CryptSignAndEncryptMessage

The CryptSignAndEncryptMessage function creates a hash of the specified content, signs the hash, encrypts the content and the signed hash, and then encodes the encrypted content and signed hash (encrypted message). The result is the same as if you first signed and then encrypted separately.

#include <wincrypt.h>
BOOL WINAPI CryptSignAndEncryptMessage(
  PCRYPT_SIGN_MESSAGE_PARA pSignPara,       // in
  PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara, // in
  DWORD cRecipientCert,                     // in
  PCCERT_CONTEXT rgpRecipientCert[ ],       // in
  const BYTE *pbToBeSignedAndEncrypted,     // in
  DWORD cbToBeSignedAndEncrypted,           // in
  BYTE *pbSignedAndEncryptedBlob,           // out
  DWORD *pcbSignedAndEncryptedBlob          // in/out
);

Parameters

pSignPara
Pointer to the signature parameters. For details, see Simplified Message Data Structures.
pEncryptPara
Pointer to the encryption parameters. For details, see Simplified Message Data Structures.
cRecipientCert
Number of array elements in rgpRecipientCert[].
rgpRecipientCert[]
Array of pointers to the certificate contexts of the intended recipients of the message.
pbToBeSignedAndEncrypted
Pointer to the content that is to be signed and encrypted.
cbToBeSignedAndEncrypted
Size, in bytes, of the content located at *pbToBeSignedAndEncrypted.
pbSignedAndEncryptedBlob
Pointer to a buffer that receives the encrypted and encoded message.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbSignedAndEncryptedBlob
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbSignedAndEncryptedBlob parameter. When the function returns, this variable contains the size, in bytes, of the signed and encrypted message copied to *pbSignedAndEncryptedBlob.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptSignMessage and CryptEncryptMessage may be propagated to this function.

This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbSignedAndEncryptedBlob parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbSignedAndEncryptedBlob.

Example

// EXAMPLE CODE FOR USING CryptSignAndEncryptMessage() to sign and
// encrypt a single message.

// Assume that the application already knows the addresses of the
// recipient certification array (rgpRecipientCert[]), the number of elements
// in rgcRecipientCert[] (cRecipientCert), the message to be signed and
// encrypted (pbToBeSignedAndEncrypted), and the size of the message
// (cbToBeSignedAndEnctypted).

// Set up the variables.
CRYPT_SIGN_MESSAGE_PARA     SignPara;       //Struct initialized
                                            //   elsewhere
CRYPT_ENCRYPT_MESSAGE_PARA  EncryptPara;    //Struct initialized
                                            //   elsewhere
DWORD            cRecipientCert = 1;        // Initialized elsewhere
PCCERT_CONTEXT   rgpRecipientCert[1];       // Initialized elsewhere
const BYTE*      pbToBeSignedAndEncrypted;  // Initialized
                                            //   elsewhere
DWORD            cbToBeSignedAndEncrypted;  // Initialized
                                            //   elsewhere
DWORD            cbSignedAndEncryptedBlob;

// Call CryptSignAndEncryptMessage to get the size of the signed and
// encrypted message.
BOOL             fReturn =  FALSE;

fReturn = CryptSignAndEncryptMessage(&SignPara, &EncryptPara,
          cRecipientCert, rgpRecipientCert,
          pbToBeSignedAndEncrypted, cbToBeSignedAndEncrypted,
          NULL, &cbSignedAndEncryptedBlob);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the call succeeded, the size of the signed and encrypted message,
// in bytes, now resides in cbSignedAndEncryptedBlob.

// Malloc memory for the size of the signed and encrypted message.
BYTE* pbSignedAndEncryptedBlob;

pbSignedAndEncryptedBlob = (BYTE*)malloc(cbSignedAndEncryptedBlob);
if(pbSignedAndEncryptedBlob == NULL)
    ;// Handle the memory allocation error.

// Call CryptSignAndEncryptMessage to return the signed and encrypted
// message.
fReturn = CryptSignAndEncryptMessage(&SignPara, &EncryptPara,
          cRecipientCert, rgpRecipientCert,
          pbToBeSignedAndEncrypted, cbToBeSignedAndEncrypted,
          pbSignedAndEncryptedBlob, &cbSignedAndEncryptedBlob);
if(fReturn != TRUE)
    ;// Function call failed.  Handle the error.

// If the function succeeded, the signed and encrypted message is now
// at the location pointed to by pbSignedAndEncryptedBlob.

// Process the message.
...

// Free memory.
free (pbSignedAndEncryptedBlob);

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSignMessage


CryptSignMessage

The CryptSignMessage function creates a hash of the specified content, signs the hash, and then encodes both the original content and the signed hash (message).

#include <wincrypt.h>
BOOL WINAPI CryptSignMessage(
  PCRYPT_SIGN_MESSAGE_PARA pSignPara, // in
  BOOL fDetachedSignature,            // in
  DWORD cToBeSigned,                  // in
  const BYTE *rgpbToBeSigned[ ],      // in
  DWORD rgcbToBeSigned[ ],            // in
  BYTE *pbSignedBlob,                 // out
  DWORD *pcbSignedBlob                // in/out
);

Parameters

pSignPara
Pointer to the signature parameters. For details, see Simplified Message Data Structures.
fDetachedSignature
TRUE if this is to be a detached signature. Otherwise it should be set to FALSE. If this parameter is set to TRUE, only the signed hash is encoded in pbSignedBlob. Otherwise, both rgpbToBeSigned[] and the signed hash are encoded.
cToBeSigned
Count of the number of array elements in rgpbToBeSigned[] and rgcbToBeSigned[]. This parameter must be set to one (1) unless fDetachedSignature is set to TRUE.
rgpbToBeSigned[]
Array of pointers that point to the contents to be signed.
rgcbToBeSigned[]
Array of sizes, in bytes, of the contents pointed to in rgpbToBeSigned[].
pbSignedBlob
Pointer to a buffer that receives only the encoded signed hash if fDetachedSignature is TRUE, or receives both the encoded content and signed hash if fDetachedSignature is FALSE.

This parameter can be NULL to set the size of this information for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbSignedBlob
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbSignedBlob parameter. When the function returns, this variable contains the size, in bytes, of the signed and encoded message copied to *pbSignedBlob.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, and CryptSignHash may be propagated to this function. This function has the following error codes.

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbSignedBlob parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbSignedBlob.
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported. Invalid cbSize in *pSignPara.
CRYPT_E_NO_KEY_PROPERTY | The pSigningCert in *pSignPara doesn't have a CERT_KEY_PROV_INFO_PROP_ID or CERT_KEY_CONTEXT_PROP_ID property.
CRYPT_E_OSS_ERROR | Message ASN.1 encoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.

Example

See Example Code Using CryptSignMessage.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptSignAndEncryptMessage


CryptVerifyDetachedMessageHash

The CryptVerifyDetachedMessageHash function verifies a detached hash.

#include <wincrypt.h>
BOOL WINAPI CryptVerifyDetachedMessageHash(
  PCRYPT_HASH_MESSAGE_PARA pHashPara, // in
  BYTE *pbDetachedHashBlob,           // in
  DWORD cbDetachedHashBlob,           // in
  DWORD cToBeHashed,                  // in
  const BYTE *rgpbToBeHashed[ ],      // in
  DWORD rgcbToBeHashed[ ],            // in
  BYTE *pbComputedHash,               // out, optional
  DWORD *pcbComputedHash              // in/out, optional
);

Parameters

pHashPara
Pointer to the hash parameters. For details, see Simplified Message Data Structures.
pbDetachedHashBlob
Pointer to the encoded, detached hash (without content).
cbDetachedHashBlob
Size, in bytes, of the detached hash.
cToBeHashed
Number of elements in the rgpbToBeHashed[] and rgcbToBeHashed[] arrays.
rgpbToBeHashed[]
Array of pointers to the contents to be hashed.
rgcbToBeHashed[]
Array of sizes, in bytes, for the contents pointed to by the elements of rgcbToBeHashed[].
pbComputedHash
Optional parameter. Pointer to a buffer that receives the newly computed hash.

This parameter can be NULL if the newly created hash is not needed for additional processing, or to set the size of the hash for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbComputedHash
Optional parameter. Pointers to a variable that specifies the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, this variable contains the size, in bytes, of the newly created hash copied to *pbComputedHash. A new hash will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded and the detached hash was verified. FALSE if the function failed.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, and CryptGetHashParam may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_MSG_TYPE | Not a hashed cryptographic message.
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported. Invalid cbSize in *pHashPara.
ERROR_MORE_DATA | If the buffer specified by the pbComputedHash parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbComputedHash.

Example

// EXAMPLE CODE FOR USING CryptVerifyDetachedMessageHash() to verify a
// single detached hash. The computed hash is not needed and
// will not be returned.

// Assume that the application already knows the address of the
// target detached hash (pbDetachedHashBlob) and its size
// (cbDetachedHashBlob), the address of the content to be hashed for
// comparison (rgpbToBeHashed[]), the number of elements in the array
// (cToBeHashed), and the size of each of the elements
// (rgcbToBeHashed[]).

// Set up the variables.
CRYPT_HASH_MESSAGE_PARA        HashPara;    // Struct initialized elsewhere
BYTE*                pbDetachedHashBlob;    // Initialized elsewhere
DWORD                cbDetachedHashBlob;    // Initialized elsewhere
DWORD                cToBeHashed = 1;
const BYTE*          rgpbToBeHashed[1];     // Initialized elsewhere
DWORD                rgcbToBeHashed[1];     // Initialized elsewhere
BOOL                 fReturn =    FALSE;

// Call CryptVerifyDetachedMessageHash to verify the detached hash.
fReturn = CryptVerifyDetachedMessageHash(&HashPara,
          pbDetachedHashBlob, cbDetachedHashBlob,
          cToBeHashed, rgpbToBeHashed,rgcbToBeHashed,
          NULL, NULL);
if(fReturn != TRUE)
    ;// The hash was not verified. Handle the condition.

// If the function succeeded, the detached hash was verified.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyMessageHash


CryptVerifyDetachedMessageSignature

The CryptVerifyDetachedMessageSignature function verifies a signed message containing a detached signature or signatures.

#include <wincrypt.h>
BOOL WINAPI CryptVerifyDetachedMessageSignature(
  CRYPT_VERIFY_MESSAGE_PARA pVerifyPara,  // in
  DWORD dwSignerIndex,                    // in
  const BYTE * pbDetachedSignBlob,        // in
  DWORD cbDetachedSignBlob,               // in
  DWORD cToBeSigned,                      // in
  const BYTE *rgpbToBeSigned[ ],          // in
  DWORD *rgcbToBeSigned[ ],               // in
  PCCERT_CONTEXT *ppSignerCert            // out, optional
);

Parameters

pVerifyPara
A pointer to the verify parameters. For details, see Simplified Message Data Structures.
dwSignerIndex
There can be more than one signature. This is an index to the desired signature. The function can be called repeatedly, incrementing dwSignerIndex each time. If the function returns FALSE, and GetLastError returns CRYPT_E_NO_SIGNER, the previous call got the last signer of the message.
pbDetachedSignBlob
A pointer to the encoded message containing only signatures (without content).
cbDetachedSignBlob
The size, in bytes, of the detached signature.
cToBeSigned
The number of array elements in rgpbToBeSigned[] and rgcbToBeSigned[].
rgpbToBeSigned[]
An array of pointers to the contents to be hashed.
rgcbToBeSigned[]
An array of sizes, in bytes, for the contents pointed to in rgpbToBeSigned[].
ppSignerCert
An optional parameter, it is a pointer to the certificate context pointer of the signer. A pointer will not be returned if this parameter is NULL.

Return Values

TRUE if the function succeeded and the detached signature was verified. FALSE if the function failed to verify the signature.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, CryptVerifySignature, and CryptImportKey may be propagated to this function. This function has the following error codes:

Error code | Description
E_INVALIDARG | Invalid message and certificate encoding types. Currently only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING_TYPE are supported. Invalid cbSize in *pVerifyPara.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_MSG_TYPE | Not a signed cryptographic message.
CRYPT_E_NO_SIGNER | The message doesn't have any signers or a signer for the specified dwSignerIndex.
NTE_BAD_ALGID | The message was hashed and signed using an algorithm we don't know about or support.
NTE_BAD_SIGNATURE | The message's signature was not verified.

Example

// EXAMPLE CODE FOR USING CryptVerifyDetachedMessageSignature() to
// verify a message's signatures. The signer's certificates are not
// required and won't be returned.

// Assume that the application already knows the address of the
// target detached signature blob (pbDetachedSignBlob) and its size
// (cbDetachedsignBlob), the address of the array of signatures to be
// verified (rgpbToBeSigned[]), the number of elements in the array
// (cToBeSigned), and the size of each of the elements
// (rgcbToBeSigned[]).

// Set up the variables.
CRYPT_VERIFY_MESSAGE_PARA    VerifyPara;      // Struct initialized elsewhere
DWORD                dwSignerIndex = 0;
const BYTE*          pbDetachedSignBlob;      // Initialized elsewhere
DWORD                cbDetachedSignBlob;      // Initialized elsewhere
DWORD                cToBeSigned = 3;         // Initialized elsewhere
const BYTE*          rgpbToBeSigned[3];       // Initialized elsewhere
DWORD                rgcbToBeSigned[3];       // Initialized elsewhere
BOOL                 fReturn =    FALSE;
DWORD                dwErrorCode;

// Call CryptVerifyDetachedMessageSignature to verify the detached
// signatures.
while(TRUE)
{
    fReturn = CryptVerifyDetachedMessageSignature(&VerifyPara,
              dwSignerIndex, pbDetachedSignBlob,
              cbDetachedSignBlob, cToBeSigned,
              rgpbToBeSigned,rgcbToBeSigned, NULL);
    if(fReturn != TRUE)
    {
        dwErrorCode = GetLastError();
        if(dwErrorCode == CRYPT_E_NO_SIGNER)
        {
            cout << "Done verifying signatures";
            break;
        }
        else
        {
            // A signer was not verified or an error occurred.
            // Handle the condition.
        }
    }
    dwSignerIndex ++;
}

// If dwErrorCode = CRYPT_E_NO_SIGNER at this point, the function succeeded,
// and all the signatures were verified.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyMessageSignature


CryptVerifyMessageHash

The CryptVerifyMessageHash function verifies the hash of some specified content (message).

#include <wincrypt.h>
BOOL WINAPI CryptVerifyMessageHash(
  PCRYPT_HASH_MESSAGE_PARA pHashPara, // in
  BYTE *pbHashedBlob,                 // in
  DWORD cbHashedBlob,                 // in
  BYTE *pbToBeHashed,                 // out, optional
  DWORD *pcbToBeHashed,               // in/out, optional
  BYTE *pbComputedHash,               // out, optional
  DWORD *pcbComputedHash              // in/out, optional
);

Parameters

pHashPara
Pointer to the hash parameters. For details, see Simplified Message Data Structures.
pbHashedBlob
Pointer to the content and original hash.
cbHashedBlob
Size, in bytes, of the content and original hash.
pbToBeHashed
Optional parameter. Pointer to a buffer that receives the original content that was hashed.

This parameter can be NULL if the original content is not needed for additional processing, or to set the size of the original content for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbToBeHashed
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbToBeHashed parameter. When the function returns, this variable contains the size, in bytes, of the original content copied to pbToBeHashed. The original content will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

pbComputedHash
Optional parameter. Pointer to a buffer that receives the newly computed hash. This parameter can be NULL if the newly created hash is not needed for additional processing, or to set the size of the original content for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.
pcbComputedHash
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, this variable contains the size, in bytes, of the newly created hash copied to *pbComputedHash. The newly created hash will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

Return Values

TRUE if the function succeeded and the hash was verified. FALSE if the function failed to verify the hash.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, and CryptGetHashParam may be propagated to this function. This function has the following error codes.

Error code | Description
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_MSG_TYPE | Not a hashed cryptographic message.
E_INVALIDARG | Invalid message encoding type. Currently only PKCS_7_ASN_ENCODING is supported. Invalid cbSize in *pHashPara.
ERROR_MORE_DATA | If the buffer specified by the pbToBeHashed parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbToBeHashed.

Example

// EXAMPLE CODE FOR USING CryptVerifyMessageHash() to verify a single
// hash. The original content and computed hash is not needed and
// will not be returned.

// Assume that the application already knows the address of the
// target hashed blob (pbHashedBlob) and its size (cbHashedBlob).

// Set up the variables.
CRYPT_HASH_MESSAGE_PARA  HashPara;        // Struct initialized
                                          //   elsewhere
BYTE*                    pbHashedBlob;    // Initialized elsewhere
DWORD                    cbHashedBlob;    // Initialized elsewhere
BOOL                 fReturn =    FALSE;

// Call CryptVerifyMessageHash to verify the hash.
fReturn = CryptVerifyMessageHash(&HashPara, pbHashedBlob,
          cbHashedBlob, NULL, NULL, NULL, NULL);
if(fReturn != TRUE)
{
    // The hash was not verified or an error occurred.
    // Handle the condition.
}

// If the function succeeded, the hash was verified.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyDetachedMessageHash


CryptVerifyMessageSignature

The CryptVerifyMessageSignature function verifies the signature on a signed message.

#include <wincrypt.h>
BOOL WINAPI CryptVerifyMessageSignature(
  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, // in
  DWORD dwSignerIndex,                    // in
  const BYTE *pbSignedBlob,               // in
  DWORD cbSignedBlob,                     // in
  BYTE *pbDecoded,                        // out, optional
  DWORD *pcbDecoded,                      // in/out, optional
  PCCERT_CONTEXT *ppSignerCert            // out, optional
);

Parameters

pVerifyPara
Pointer to the verify parameters. For details, see Simplified Message Data Structures.
dwSignerIndex
This is an index to the desired signature. There can be more than one signature. CryptVerifyMessageSignature can be called repeatedly, incrementing dwSignerIndex each time. Set this parameter to zero for the first signer, or if there is only one signer. If the function returns FALSE, and GetLastError returns CRYPT_E_NO_SIGNER, the previous call got the last signer of the message.
pbSignedBlob
Pointer to the signed message.
cbSignedBlob
Size, in bytes, of the signed message.
pbDecoded
Optional parameter. Pointer to a buffer that receives the decoded message.

This parameter can be NULL if the decoded message is not needed for additional processing, or to set the size of the message for memory allocation purposes. For more information, see Common In/Out Parameter Conventions.

pcbDecoded
Optional parameter. Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pbComputedHash parameter. When the function returns, this variable contains the size, in bytes, of the decoded message copied to pbDecoded. The decoded message will not be returned if this parameter is NULL.

Note that when processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to insure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

ppSignerCert
Optional parameter, it is a pointer to the certificate context pointer of the signer. This parameter can be NULL, indicating that the caller isn't interested in getting the CERT_CONTEXT of the signer.

Return Values

TRUE if the function succeeded and the signature was verified. FALSE if the function failed to verify the signature. Call GetLastError to see the reason for the failure.

Call GetLastError to see the reason for any failures. Note that errors from the called functions CryptCreateHash, CryptHashData, CryptVerifySignature, and CryptImportKey may be propagated to this function. This function has the following error codes:

Error code | Description
ERROR_MORE_DATA | If the buffer specified by the pbDecoded parameter is not large enough to hold the returned data, the function sets the ERROR_MORE_DATA code, and stores the required buffer size, in bytes, into the variable pointed to by pcbDecoded.
E_INVALIDARG | Invalid message and certificate encoding types. Currently only PKCS_7_ASN_ENCODING and X509_ASN_ENCODING_TYPE are supported. Invalid cbSize in *pVerifyPara.
CRYPT_E_OSS_ERROR | Message ASN.1 decoding error. Note, to get the OSS error subtract CRYPT_E_OSS_ERROR from the returned error and see asn1code.h for details on the error.
CRYPT_E_UNEXPECTED_ MSG_TYPE | Not a signed cryptographic message.
CRYPT_E_NO_SIGNER | The message doesn't have any signers or a signer for the specified dwSignerIndex.
NTE_BAD_ALGID | The message was hashed and signed using an algorithm we don't know about or support.
NTE_BAD_SIGNATURE | The message's signature was not verified.

Remarks

For a verified signer and message, **ppSignerCert is updated with the CERT_CONTEXT of the signer. It must be freed by calling CertFreeCertificateContext. Otherwise, *ppSignerCert is set to NULL.

For a message containing only certificates and CRLs, pcbDecoded should be set to NULL.

Example

See Example Code Using CryptVerifyMessageSignature.

QuickInfo

Windows NT: Requires version 4.0 SP3 or later. Available also in IE 3.02 and later.
Windows: Requires Windows 98 (or Windows 95 with IE 3.02 or later).
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use crypt32.lib.

See Also

CryptVerifyDetachedMessageSignature


Remote Object Retrieval Functions

These functions allow the user to retrieve a Public Key Infrastructure (PKI) object, get a Uniform Resource Locator (URL) to a certificate, CTL, or CRL, or to extract a URL from an object.

The following functions are included in this category and can also be found in Wincrypt.h.

Function | Description
CryptGetObjectUrl | Gets the URL of the remote object from a certificate, CTL, or CRL.
CryptRetrieveObjectByUrl | Retrieves the PKI object where the location is given by an URL.


CryptGetObjectUrl

[This is preliminary documentation and subject to change.]

The CryptGetObjectUrl function gets the URL of the remote object from a certificate, CTL, or CRL.

The function takes the object, decodes it, and provides a pointer to an array of URLs from the object. For example; from a certificate, a CRL distribution list (URLs) would be in the array.

#include <wincrypt.h>
BOOL WINAPI CryptGetObjectUrl(
  LPCSTR pszUrlOid,                // in
  LPVOID pvPara,                   // in
  DWORD dwFlags,                   // in
  PCRYPT_URL_ARRAY pUrlArray,      // out/optional
  DWORD* pcbUrlArray,              // in/out
  PCRYPT_URL_INFO pUrlInfo,        // out/optional
  DWORD* pcbUrlInfo,               // in/out/optional
  LPVOID pvReserved                // in/optional
);

Parameters

pszUrlOid
Pointer to the object identifier that identifies the URL being requested. If the HIWORD of the pszUrlOid parameter is zero, the LOWORD specifies the integer identifier for the type of the given structure.

OIDs extend the functionality of the CryptoAPI. See OID Overview for additional information.

Support for registering the new functionality in a system registry must be provided in the new DLL along with the new function. See Registering the New Functionality.

See The following table is a list of currently supported OIDs:
OID OID value Meaning
URL_OID_
CERTIFICATE_
ISSUER 		(LPCSTR)1 Given a certificate, provides the URL of the certificate issuer. This will be retrieved from the authority info access extension or property on the certificate.
URL_OID_
CERTIFICATE_CRL_
DIST_POINT 		(LPCSTR)2 Given a certificate, provides a list URLs of the CRL distribution points. This will be retrieved from the CRL distribution point extension or property on the certificate.
URL_OID_CTL_
ISSUER 		(LPCSTR)3 Given a CTL, provides the URL of the CTL issuer. This will be retrieved from an authority info access attribute method encoded in each signer info in the PKCS #7 (CTL).
URL_OID_CTL_
NEXT_UPDATE 		(LPCSTR)4 Given a CTL, provides the URL of the next update of that CTL. This is retrieved from an authority info access CTL extension, property, or signer info attribute method.
URL_OID_CRL_
ISSUER 		(LPCSTR)5 Given a CRL, provides the URL of the CRL issuer. This is retrieved from a property on the CRL that was inherited from the subject certificate (either from the subject certificate issuer or the subject certificate distribution point extension). It is encoded as an authority info access extension method.

pvPara
If pszUrlOid is URL_OID_CERTIFICATE_ISSUER;
pvPara is a PCCERT_CONTEXT. Pointer to a certificate whose issuer's URL is being requested. This is retrieved from the authority info access extension or property on the certificate.
If pszUrlOid is URL_OID_CERTIFICATE_CRL_DIST_POINT;
pvPara is a PCCERT_CONTEXT. Pointer to a certificate whose CRL distribution point is requested. This is retrieved from the CRL distribution point extension or property on the certificate.
If pszUrlOid is URL_OID_CTL_ISSUER;
pvPara is a PCCTL_CONTEXT. Pointer to a Signer Index CTL whose issuer's URL (identified by the signer index) is requested. This is retrieved from the authority info access attribute method encoded in each signer info in the PKCS #7 (CTL).
If pszUrlOid is URL_OID_CTL_NEXT_UPDATE;
pvPara is a PCCTL_CONTEXT. Pointer to a Signer Index CTL, whose next update URL is requested, and an optional signer index, in case it is needed to check the signer info attributes. This is retrieved from the authority info access CTL extension, property, or signer info attribute method.
If pszUrlOid is URL_OID_CRL ISSUER;
pvPara is a PCCRL_CONTEXT. Pointer to a CRL whose issuer's URL is requested. This is retrieved from a property on the CRL which is inherited from the subject certificate (either from the subject certificate issuer or the subject certificate distribution point extension). It is encoded as an authority info access extension method.
dwFlags
Flag values. This parameter is used to get the URL locator for an object.
Flag value Description
CRYPT_GET_URL_
FROM_PROPERTY 		Locates the URL from the object's property (the location of the data).
CRYPT_GET_URL_
FROM_EXTENSION 		Locates the URL from the object's extension.
CRYPT_GET_URL_
FROM_UNAUTH_
ATTRIBUTE 		Locates the URL from an unauthenticated attribute from the signer info data.
CRYPT_GET_URL_
FROM_AUTH_
ATTRIBUTE 		Locates the URL from an authenticated attribute from the signer info data.

pUrlArray
Pointer to a buffer that receives the data for the value entry. This parameter can be NULL if the data is not required.

For more information, see Common In/Out Parameter Conventions.

pcbUrlArray
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pUrlArray parameter. When the function returns, the variable pointed to by the pcbUrlArray parameter contains the number of bytes stored in the buffer. This parameter can be NULL, only if pUrlArray is NULL.
pUrlInfo
Pointer to a buffer that receives the data for the value entry. This parameter can be NULL if the data is not required.

For more information, see Common In/Out Parameter Conventions.

pcbUrlInfo
Pointer to a variable that specifies the size, in bytes, of the buffer pointed to by the pUrlInfo parameter. When the function returns, the variable pointed to by pcbUrlInfo paramater contains the number of bytes stored in the buffer. This parameter can be NULL, only if pUrlInfo is NULL.

Note When processing the data returned in the buffer, applications need to use the actual size of the data returned. The actual size may be slightly smaller than the size of the buffer specified on input. (On input, buffer sizes are usually specified large enough to ensure that the largest possible output data will fit in the buffer.) On output, the variable pointed to by this parameter is updated to reflect the actual size of the data copied to the buffer.

pvReserved
This parameter is reserved for future use and should always be set to NULL.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Remarks

CryptGetObjectUrl has the same signature as UrlDllGetObjectUrl. The developer can implement a UrlDllGetObjectUrl with the signature of CryptGetObjectUrl and install it for the OID.

Example

// EXAMPLE CODE FOR USING CryptGetObjectUrl().
// Assume that a pointer to URL in a PCCTL_CONTEXT
// (pvPara) is already known.

// Set up the variables.
LPCSTR  pszUrlOid;        // Pointer to object identifier
PCCTL_CONTEXT  *pvPara;   // Pointer to URL
DWORD dwFlags;            // Flag values
PCRYPT_URL_ARRAY  pUrlArray= NULL;
                          // Pointer to URl array- initialize to NULL
DWORD cbUrlArray;
PCRYPT_URL_INFO  pUrlInfo= NULL;
                          // Pointer to URL buffer- initialize to NULL
DWORD cbUrlInfo;
LPVOID *pvReserved;       // Reserved for future use
BOOL fResult;             // Return value- True if function successful
                          //   False if function fails

// first call to CryptGetObjectUrl to get the size of array length
fResult= CryptGetObjectUrl(
           URL_OID_CTL_ISSUER,// in- pszUrlOid- Get the URL from a CTL
                              //   ISSUER
           pvPara,            // in- Pointer to a signer index
                              //  initialized elsewhere
           CRYPT_GET_URL_FROM_PROPERTY,
                              // in- dwFlags
           NULL,              // out/optional- pUrlArray- set to NULL
                              //   to allocate memory
           &cbUrlArray,       // in/out- pUrlArray array length
           NULL,              // out/optional- pUrlInfo- set to NULL
                              //   to allocate memory
           &cbUrlInfo,        // in/out/optional- pUrlInfo size
           NULL);             // in/optional- pvReserved

if (fResult){                 // returned value is TRUE
                              //   CryptGetObjectUrl is successful
  cout<< "First call to CryptGetObjectUrl successful"<< endl;
  pUrlArray = (PCRYPT_URL_ARRAY)malloc (cbUrlArray);
  pUrlInfo = (PCRYPT_URL_INFO)malloc (cbUrlInfo);
  cout<< "memory allocated" << endl;
}
else {                        // returned value is FALSE
  cout<< "First call to CryptGetObjectUrl failed"<< endl;
}

// Function call to get the URL
fResult= CryptGetObjectUrl(
           URL_OID_CTL_ISSUER,// in- pszUrlOid- Get the URL from a CTL
                              //   ISSUER
           pvPara,            // in- Pointer to a signer index
                              //  initialized elsewhere
           CRYPT_GET_URL_FROM_PROPERTY,
                              // in- dwFlags
           pUrlArray,         // out/optional- pUrlArray
           &cbUrlArray,       // in/out- pUrlArray array length
           pUrlInfo,          // out/optional- pUrlInfo
           &cbUrlInfo,        // in/out/optional- pUrlInfo size
           NULL);             // in/optional- pvReserved

if (fResult){                 // returned value is TRUE
                              //   CryptGetObjectUrl is successful
  cout<< "Second call to CryptGetObjectUrl successful"<< endl
      << "The URL is "<< pUrlInfo<< endl;
}
else {                        // returned value is FALSE
  cout<< "Second call to CryptGetObjectUrl failed"<< endl
      << "error code = "<< GetLastError<< endl;
}

// free memory
free(pUrlArray);
free(pUrlInfo);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use cryptnet.lib.


CryptRetrieveObjectByUrl

[This is preliminary documentation and subject to change.]

The CryptRetrieveObjectByUrl function retrieves the PKI object where the location is given by an URL.

These remote objects are in encoded format and are retrieved in a "context" form.

#include <wincrypt.h>
BOOL WINAPI CryptRetrieveObjectByUrl(
  LPCTSTR pszUrl,                  // in
  LPCSTR pszObjectOid,             // in
  DWORD dwRetrievalFlags,          // in
  DWORD dwTimeout,                 // in
  LPVOID *ppvObject,               // out
  HCRYPTASYNC hAsyncRetrieve,      // in
  PCRYPT_CREDENTIALS pCredentials, // in/optional
  LPVOID pvVerify,                 // in/optional
  LPVOID pvReserved                // in/optional
);

Parameters

pszUrl
A LPCTSTR address of a valid URL from which to retrieve the PKI object(s). The following schemes are supported:
  • ldap
  • http
  • ftp
  • file
pszObjectOid
Pointer to the object identifier (OID) of the object(s) to be retrieved. The valid OIDs are as follows:
OID Value | Description | Returned ppvObject type
NULL | blob | Encoded bits are returned in a single buffer with a count, array of pointers, and data which must be freed with CryptMemFree.
CONTEXT_OID_
CERTIFICATE 		certificate PCERT_CONTEXT for single object retrieval. HCERTSTORE, which contains the certificates, for multiple object retrieval.
CONTEXT_OID_
CRL 		CRL PCRL_CONTEXT for single object retrieval. HCERTSTORE, which contains the CRLs, for multiple object retrieval.
CONTEXT_OID_
CTL 		CTL PCTL_CONTEXT for single object retrieval. HCERTSTORE, which contains the CTLs, for multiple object retrieval.
CONTEXT_OID_
PKCS7 		PKCS7 HCERTSTORE containing the object from the message.
CONTEXT_OID_
CAPI2_ANY 		Function will determine appropriate item HCERTSTORE containing the object.

dwRetrievalFlags
Retrieval flag values. The flag determines whether the cached URL or a URL retrieved from the wire URL should be utilized. The form in which objects are returned is determined by the pszObjectOid.
Flag value Description
CRYPT_RETRIEVE_
MULTIPLE_OBJECTS 		Retrieves multiple objects if available. All objects must be of a homogeneous object type as determined by the pszObjectOid, unless the OID Value is CONTEXT_OID_CAPI2_ANY.
CRYPT_CACHE_
ONLY_RETRIEVAL 		Retrieves the encoded bits from the URL cache only. Do not use the wire to retrieve the URL.
CRYPT_WIRE_ONLY_
RETRIEVAL 		Retrieves the encoded bits from the wire only. Does not use the URL cache.
CRYPT_DONT_
CACHE_RESULT 		Does not store the retrieved encoded bits to the URL cache. If this flag is not set, the retrieved URL is cached.
CRYPT_ASYNC_
RETRIEVAL 		Retrieves the object(s) asynchronously. If this flag is not set, hAsyncRetrieve must be NULL. (This flag is not supported in Windows NT® 5.0 Beta).
CRYPT_VERIFY_
CONTEXT_
SIGNATURE 		Gets signature verification on the context created. In this case pszObjectOid must be non-NULL and pvVerify points to the signer certificate context.
CRYPT_VERIFY_
DATA_HASH 		Gets verification of the blob data retrieved by the protocol. The pvVerify points to an URL_DATA_HASH structure (This flag is not supported in Windows NT 5.0 Beta).

dwTimeout
Specifies the maximum number of milliseconds to wait for retrieval. If a value of zero is specified, this function does not time-out. If the URL scheme is file, dwTimeout is not used.
ppvObject
Address of pointer variable of the returned object. The return type can be one of the supported type, shown in pszObjectOid.
hAsyncRetrieve
Async handle by a scheme provider that supports asynchronous retrieval. If dwRetrievalFlags is not set to CRYPT_ASYNC_RETRIEVAL, this parameter must be NULL. Asynchronous retrieval is not supported in Microsoft® Windows NT® 5.0 Beta 2. Set hAsyncRetrieve to NULL.
pCredentials
Pointer to the Credentials structure when accessing the URL. The only type of credentials currently supported are username and password credentials. pCredentials is used only when the object is retrieved from the wire. Do not use pCredentials when using cache-only retrieval (set pCredentials to NULL). If the URL scheme is file, pCredentials is not used.
pvVerify
Pointer to a verification object. This object is a function of the dwRetrievalFlags. pvVerify can be NULL, indicating the caller isn't interested in getting the certificate context or index of the signer if dwRetrievalFlags is CRYPT_VERIFY_CONTEXT_SIGNATURE or CRYPT_VERIFY_DATA_HASH.
pvReserved
This parameter is reserved for future use and should always be set to NULL.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Remarks

The remote object retrieval manager exposes two provider models. One is the "Scheme Provider" model which allows for installable protocol providers as defined by the URL scheme e.g. ldap, http, ftp, file. The scheme provider entry point is the same as the CryptRetrieveObjectByUrl; however, the *ppvObject returned is ALWAYS a counted array of encoded bits (one per object retrieved).

The second provider model is the "Context Provider" model that allows for installable creators of the context handles (objects) based on the retrieved encoded bits. These are dispatched based on the object OID given in the call to CryptRetrieveObjectByUrl.

This functions supports multiple URL schemes such as "http:", "ftp:", "ldap:", "file:" as well as newly defined schemes.

Retrieval of individual PKI objects, such as certificates, trusts lists, revocation lists, PKCS #7 messages, and multiple homogenous objects is possible.

Example

// EXAMPLE CODE FOR USING CryptRetrieveObjectByUrl().
// Assume that a pointer to the URL (pszUrl) and the credentials
// structure (pCredentials) is already known.

// Set up the variables.
LPCTSTR pszUrl;                 // Pointer to a valid URL
LPCSTR pszObjectOid;            // Pointer to an OID
DWORD dwRetrievalFlags;         // Retrieval flag
DWORD dwTimeout;                // Timeout value (milliseconds)
LPVOID* ppvObject;              // Return address
HCRYPTASYNC hAsyncRetrieve;     // Set to NULL- not utilized in
                                //   Windows NT 5.0 Beta
PCRYPT_CREDENTIALS pCredentials;// Pointer to Credentials structure
PCRL_CONTEXT pvVerify;          // Pointer to Verification object
LPVOID pvReserved;              // NULL- reserved for future use
BOOL fResult;                   // Return value- True if function
                                //   successful
                                //   False if function fails

// call to CryptRetrieveObjectByUrl to get the URL object
fResult= CryptRetrieveObjectByUrl(
           pszUrl,              // in- pszUrl- initialized elsewhere
           CONTEXT_OID_CRL,     // in- OID
           CRYPT_CACHE_ONLY_RETRIEVAL,
                                // in- Use the cache only. Do not go
                                //   onto the wire to retrieve the
                                //   URL.
           0,                   // in- timeout set 0
           ppvObject,           // out- Address of returned object
           NULL,                // in- hAsyncRetrieve- set to NULL
           NULL,                // in/optional- pCredentials set to
                                //   NULL, using cache only
           NULL,                // in/optional- pvVerify- not
                                //   interested in getting signer's
                                //   verification
           NULL);               // in/optional- pvReserved

if (fResult){                   // returned value is TRUE
                                //   CryptGetObjectUrl is successful
  cout<< "Call to CryptRetrieveObjectByUrl successful"<< endl
      << "The object, "<< ppvObject<< endl
      << "is at "<< &ppvObject<< endl;
 }
else {                          // returned value is FALSE
  cout<< "Call to CryptRetrieveObjectByUrl failed"<< endl
      << "error code = "<< GetLastError<< endl;
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use cryptnet.lib.


Crypt Time Valid Object Retrieval Functions

The purpose of these functions is to flush or to retrieve a time valid object (CTL, CRL, or certificate). Since objects have a valid time duration, it is possible for an object to expire and no longer be valid. An object is valid only for the period of time specified by the Certification Authority (CA) that issued the certificate.

The following functions are included in this category and the signatures can be found in Wincrypt.h.

Function | Description
CryptFlushTimeValidObject | Removes the retrieved object from the cache.
CryptGetTimeValidObject | Gets the object whose validity period covers the specified time value.


CryptFlushTimeValidObject

[This is preliminary documentation and subject to change.]

The CryptFlushTimeValidObject function removes the retrieved object from the cache.

#include <wincrypt.h>
BOOL WINAPI CryptFlushTimeValidObject(
  LPCSTR pszFlushTimeValidOid,     // in
  LPVOID pvPara,                   // in
  PCCERT_CONTEXT pIssuer,          // in
  DWORD dwFlags,                   // in
  LPVOID pvReserved                // in
);

Parameters

pszFlushTimeValidOid
Pointer to the object identifier defining the pvPara context type. If the HIWORD of the pszFlushTimeValidOid parameter is zero, the LOWORD specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

OIDs extend the functionality of the CryptoAPI. See OID Overview for additional information.

For more details, see the table in CryptEncodeObject/CryptDecodeObject Functions that relates object identifier strings and predefined constants to their corresponding data structures.

The following table lists currently supported OIDs:
OID | Meaning
TIME_VALID_OID_FLUSH_CTL | Flushes the time valid CTL from the cache.
TIME_VALID_OID_FLUSH_CRL | Flushes the time valid CRL from the cache.
TIME_VALID_OID_FLUSH_CRL_
FROM_CERT 		Flushes the time valid CRL from the certificate.

pvPara
If the pvPara is not correct for the pszFlushTimeValidOid, program behavior is unspecified.
If the pszFlushTimeValidOid is TIME_VALID_OID_FLUSH_CTL;
pvPara is a PCCTL_CONTEXT. The pointer is to a CTL to flush.
If the pszFlushTimeValidOid is TIME_VALID_OID_FLUSH_CRL;
pvPara is a PCCRL_CONTEXT. The pointer is to a CRL to flush.
If the pszFlushTimeValidOid is TIME_VALID_OID_FLUSH_CRL_FROM_CERT;
pvPara is a PCCERT_CONTEXT. The pointer is to a certification to flush.
pIssuer
Pointer to an issuer context.
dwFlags
Flag values. This parameter is reserved for future use and should always be set to zero.
pvReserved
This parameter is reserved for future use and must be NULL.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Remarks

TimeValidDllFlushObject has the same signature as CryptFlushTimeValidObject. The developer can implement a TimeValidDllFlushObject with the signature of CryptFlushTimeValidObject and install it for the OID.

Example

// EXAMPLE CODE FOR USING CryptFlushTimeValidObject().
// Assume that pointers to a CTL context (pvPara) and the
// certificate issuer (pIssuer) are already known.

// Set up the variables.
LPCSTR pszFlushTimeValidOid; //
PCCTL_CONTEXT pvPara;        // Pointer to a PCCTL_CONTEXT to
                             //   have the ThisUpdate and NextUpdate
                             //   times reset- a PCCTL_CONTEXT because
                             //   the OID is a CTL.
PCCERT_CONTEXT pIssuer;      // Pointer to issuer of the certificate
DWORD dwFlags;               // Flag values- future use- set to 0
LPVOID pvReserved;           // Reserved for future use- set to NULL
BOOL fResult;                // Return value- True if function
                             //   successful
                             //   False if function fails

// call to CryptFlushTimeValidObject to get the URL object
fResult= CryptFlushTimeValidObject(
           TIME_VALID_OID_FLUSH_CTL,
                          // in- pszFlushTimeValidOid
           (LPVOID)pvPara,// in- Initialized elsewhere
           pIssuer,       // in- Initialized elsewhere
           0,             // in- dwFlags- set to 0
           NULL);         // in- Reserved- set to NULL

if (fResult){             // returned value is TRUE
                          //   CryptFlushTimeValidObject is successful
  cout<< "Call to CryptFlushTimeValidObject successful"<< endl;
 }
else {                    // returned value is FALSE
  cout<< "Call to CryptFlushTimeValidObject failed"<< endl
      << "error code = "<< GetLastError<< endl;
}

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use cryptnet.lib.

See Also

CryptGetTimeValidObject


CryptGetTimeValidObject

[This is preliminary documentation and subject to change.]

The CryptGetTimeValidObject function gets the object whose validity period covers the specified time values.

The object (CTL, CRL, or certificate) is returned via the ppvObject parameter.

#include <wincrypt.h>
BOOL WINAPI CryptGetTimeValidObject(
  LPCSTR pszTimeValidOid,          // in
  LPVOID pvPara,                   // in
  PCCERT_CONTEXT pIssuer,          // in
  LPFILETIME pftValidFor,          // in/optional
  DWORD dwFlags,                   // in
  DWORD dwTimeout,                 // in
  LPVOID* ppvObject,               // out/optional
  PCRYPT_CREDENTIALS pCredentials, // in/optional
  LPVOID pvReserved                // in/optional
);

Parameters

pszTimeValidOid
Pointer to the object identifier defining the pvPara context type. If the HIWORD of the pszTimeValidOid parameter is zero, the LOWORD specifies the integer identifier for the type of the given structure. Otherwise, this parameter is a long pointer to a null-terminated string.

OIDs extend the functionality of the CryptoAPI. See OID Overview for additional information.

The following table lists currently supported OIDs:
OID Meaning
TIME_VALID_OID_
GET_CTL 		Gets the next time valid CTL.
TIME_VALID_OID_
GET_CRL 		Gets the next time valid CRL.
TIME_VALID_OID_
GET_CRL_FROM_CERT 		Gets the next time valid CRL from the certificate.

pvPara
If the pvPara is not correct for the pszTimeValidOid, program behavior is unspecified.
If the pszTimeValidOid is TIME_VALID_OID_GET_CTL;
pvPara is a PCCTL_CONTEXT. The pointer is to the current CTL.
If the pszTimeValidOid is TIME_VALID_OID_GET_CRL;
pvPara is a PCCRL_CONTEXT. The pointer is to the current CRL.
If the pszTimeValidOid is TIME_VALID_OID_GET_CRL_FROM_CERT;
pvPara is a PCCCERT_CONTEXT. The pointer is to the certificate.
pIssuer
Pointer to an issuer context.
pftValidFor
Pointer to a valid time for the object to be verified. If set to NULL the current time is used.
dwFlags
Flag values. This parameter is reserved for future use and should always be set to zero.
dwTimeout
Specifies the maximum number of milliseconds to wait for retrieval. If a value of zero is specified, this function will not time-out. This value is used in synchronous retrieval only.
ppvObject
Address of pointer variable of the returned object. The return type can be one of the supported types, shown in pszTimeValidOid. The valid times of the object are stored in the FILETIME structure of the CTL_INFO, CRL_INFO, or CERT_INFO pointed to by ppvObject. The context will be freed by calling CertFreeCTLContext, CertFreeCRLContext, or CertFreeCertificateContext.
pCredentials
Pointer to the Credentials structure when accessing the URL. The only type of credentials currently supported are username and password credentials. pCredentials is used only when the object is being retrieved from the wire. Do not use pCredentials when using cache only retrieval (set pCredentials to NULL). If the URL scheme is file, pCredentials is not used.
pvReserved
This parameter is reserved for future use and must be NULL.

Return Values

If the function succeeds, the return value is TRUE. If it does not succeed, the return value is FALSE. To retrieve extended error information, use the GetLastError function.

Remarks

TimeValidDllGetObject has the same signature as CryptGetTimeValidObject. The developer can implement a TimeValidDllGetObject with the signature of CryptGetTimeValidObject and install it for the OID.

Example

// EXAMPLE CODE FOR USING CryptGetTimeValidObject().
// Assume that pointers to a CRL context (pvPara) and the
// certificate issuer (pIssuer) are already known.

// Set up the variables.
LPCSTR pszTimeValidOid;   // Pointer to a time Valid OID
PCCRL_CONTEXT pvPara;     // Pointer to a PCCRL_CONTEXT to get the
                          //   time valid object- a PCCRL_CONTEXT
                          //   because the OID is a CRL.
PCCERT_CONTEXT pIssuer;   // Pointer to a certificate's issuer
LPFILETIME pftValidFor;   // Pointer to the FILETIME structure
DWORD dwFlags;            // Flag values- future use- set to 0
DWORD dwTimeout;          // Time out value (set to 0)-
                          //   Not used in Windows NT 5.0 Beta
PCCRL_CONTEXT* ppvObject;        // Pointer to address of the object
PCRYPT_CREDENTIALS pCredentials;
                          // Pointer to the Credentials structure
LPVOID pvReserved;        // Reserved for future use- set to NULL
BOOL fResult;             // Return value- True if function successful
                          //   False if function fails

// call to CryptGetTimeValidObject to get the
//   ThisUpdate and NextUpdate time.
fResult= CryptGetTimeValidObject(
           TIME_VALID_OID_GET_CRL,
                           // in- pszTimeValidOid
           (LPVOID)pvPara, // in- Initialized elsewhere
           pIssuer,        // in- Initialized elsewhere
           NULL,           // in/optional- pftValidFor set to NULL,
                           //   use current time.
           0,              // in- dwFlags- set to 0
           0,              // in- timeout value- set to 0
           (LPVOID*)ppvObject,
                           // out/optional-
           NULL,           // in/optional-pCredentials set to NULL,
                           //   using cache only
           NULL);          // in/optional- Reserved- set to NULL

if (fResult){              // returned value is TRUE
                           //   CryptGetTimeValidObject is successful
  cout<< "Call to CryptGetTimeValidObject successful"<< endl
      << "Pointer to the address (ppvObject) = "<< ppvObject<< endl
      << "ThisUpdate = "<< (*ppvObject)->
            pCrlInfo->ThisUpdate.dwLowDateTime<< endl
      << "NextUpdate = "<< (*ppvObject)->
            pCrlInfo->NextUpdate.dwLowDateTime<< endl<< endl;
 }
else {                     // returned value is FALSE
  cout<< "Call to CryptGetTimeValidObject failed"<< endl
      << "error code = "<< GetLastError<< endl;
}
// free memory
CertFreeCRLContext (*ppvObject);

QuickInfo

Windows NT: Requires version 5.0 or later.
Windows: Unsupported.
Windows CE: Unsupported.
Header: Declared in wincrypt.h.
Import Library: Use cryptnet.lib.

See Also

CryptFlushTimeValidObject


Data Types and Constants

This section describes some of the data types and constants that are used by the functions in the Microsoft® CryptoAPI.


ALG_ID

The ALG_ID data type is used to specify algorithm identifiers. Parameters of this data type are passed to most of the functions in the CryptoAPI. This data type is defined in the Wincrypt.h header file as:

typedef unsigned int ALG_ID;

The following table lists the algorithm identifiers that are currently defined. Authors of custom CSPs can define new values. Also, the ALG_ID used by custom CSPs for the key specs AT_KEYEXCHANGE and AT_SIGNATURE are provider dependent. Current mappings follow the table.

Constant | Description
CALG_DSS_SIGN | The digital signature algorithm
CALG_HMAC† | HMAC keyed hash algorithm
CALG_MD2† | MD2 hashing algorithm
CALG_MD4 | MD4 hashing algorithm
CALG_MD5† | MD5 hashing algorithm
CALG_SHA† | SHA hashing algorithm
CALG_SHA1† | Same as CALG_SHA
CALG_MAC† | MAC keyed hash algorithm
CALG_SSL3_SHAMD5 | SSL3 client authentication
CALG_RSA_SIGN† | RSA public-key signature algorithm
CALG_DSS_SIGN | DSA public-key signature algorithm
CALG_RSA_KEYX† | RSA public-key key exchange algorithm
CALG_DES | DES encryption algorithm
CALG_RC2† | RC2 block encryption algorithm
CALG_RC4† | RC4 stream encryption algorithm
CALG_SEAL | SEAL encryption algorithm
CALG_DH_SF | Diffie-Hellman store and forward key exchange algorithm
CALG_DH_EPHEM | Diffie-Hellman ephemeral key exchange algorithm
CALG_AGREEDKEY_ANY | Temporary algorithm identifier for handles of Diffie-Hellman agreed keys
CALG_KEA_KEYX | KEA key exchange algorithm (FORTEZZA)
CALG_SKIPJACK | Skipjack block encryption algorithm (FORTEZZA)
CALG_TEK | TEK (FORTEZZA)

† Algorithm supported by the Microsoft Base Cryptographic Provider.

For the Microsoft Base Cryptographic Provider and the Microsoft Enhanced Cryptographic Provider, the ALG_ID used for the key specs AT_KEYEXCHANGE and AT_SIGNATURE are as follows:

CALG_RSA_KEYX is used for AT_KEYEXCHANGE

CALG_RSA_SIGN is used for AT_SIGNATURE

For the Microsoft DSS Cryptographic Provider and the Diffie-Hellman Provider, the ALG_ID used for the key specs AT_KEYEXCHANGE and AT_SIGNATURE are as follows:

CALG_DH_SF is used for AT_KEYEXCHANGE

CALG_DSS_SIGN is used for AT_SIGNATURE

See Also

CRYPT_ALGORITHM_IDENTIFIER, CryptEncodeObject/CryptDecodeObject Functions,

CryptFindOIDInfo


HCRYPTHASH

The HCRYPTHASH data type is used to represent handles to hash objects. These handles are used to indicate to the CSP module which hash is being used in a particular operation. The CSP module does not enable direct manipulation of the hash values. Instead, the user manipulates the hash values through the hash handle.

HCRYPTHASH is defined in the Wincrypt.h header file as:

typedef unsigned long HCRYPTHASH;


HCRYPTKEY

The HCRYPTKEY data type is used to represent handles to cryptographic keys. These handles are used to indicate to the CSP module which key is being used in a specific operation. The CSP module does not enable direct access to the key values. Instead, the user performs functions by using the key value through the key handle.

HCRYPTKEY is defined in the Wincrypt.h header file as:

typedef unsigned long HCRYPTKEY;


HCRYPTPROV

The HCRYPTPROV data type is used to represent handles to CSPs. These handles are used to indicate which CSP module should perform the specific operation.

HCRYPTPROV is defined in the Wincrypt.h header file as:

typedef unsigned long HCRYPTPROV;


MAXUIDLEN

MAXUIDLEN is a numeric constant that specifies the maximum size for CSP names and key container names. No CSP or key container name can be longer than MAXUIDLEN characters, including the terminating zero.

MAXUIDLEN is defined in the Wincrypt.h header file as:

#define MAXUIDLEN 64


MS_DEF_PROV

MS_DEF_PROV is a string constant set to the name of the Microsoft Base Cryptographic Provider. This constant is used with the CryptAcquireContext and CryptSetProvider functions.

MS_DEF_PROV is defined in the Wincrypt.h header file as:

#define MS_DEF_PROV ("Microsoft Base Cryptographic Provider v1.0")


Data Structures

The following data structures are used by the functions contained in the Microsoft® CryptoAPI version 2.0. The structures are listed alphabetically within each of the following categories:

  • Cryptography Data Structures
  • Common Certificate Data Structures
  • X.509 Certificate Extension Data Structures
  • Low Level Message Data Structures
  • Simplified Message Data Structures
  • OID Support Data Structures


Cryptography Data Structures

The data structures in this section are used by the Cryptographic Functions and can be found in Wincrypt.h.


BLOBHEADER

The BLOBHEADER structure is located at the front of every key blob. This structure is not limited to the key blobs generated by the PROV_RSA_BASE and PROV_RSA_SIG provider types. Any additional key blob types that are defined should also specify that each key blob start with this structure.

This structure contains fields that indicate the key blob type and the algorithm that the key uses.

typedef struct _PUBLICKEYSTRUC {
    BYTE   bType;
    BYTE   bVersion;
    WORD   reserved;
    ALG_ID aiKeyAlg;
} ,PUBLICKEYSTRUC;

Members

bType
Key blob type. The only blob types currently defined are the PUBLICKEYBLOB, PRIVATEKEYBLOB, and SIMPLEBLOB blob types. Other key blob types will be defined as needed.

PUBLICKEYBLOBs are used to transport public keys, PRIVATEKEYBLOBs are used to transport public/private key pairs, and SIMPLEBLOBs are used to transport session keys.

bversion
Version number of the key blob format. This currently must always have a value of "0x02".
reserved
These 2 bytes are reserved for future use, and should be zero.
aiKeyAlg
Algorithm identifier for the key contained by the key blob. Some examples are CALG_RSA_SIGN, CALG_RSA_KEYX, CALG_RC2, and CALG_RC4.

Not all algorithm identifiers are valid with all blob types. For example, you would never export an RC4 key into a PUBLICKEYBLOB.

See Also

DSSPUBKEY, DSSSEED, RSAPUBKEY


CRYPTPROTECT_PROMPTSTRUCT

[This is preliminary documentation and subject to change.]

The CRYPTPROTECT_PROMPTSTRUCT structure provides the text of a prompt and information about when and where that prompt is to be displayed when using the CryptProtectData and CryptUnprotectData functions.

typedef struct _CRYPTPROTECT_PROMPTSTRUCT{
  DWORD      cbSize;
  DWORD      dwPromptFlags;
  HWND       hwndApp;
  LPCWSTR    szPrompt;
} CRYPTPROTECT_PROMPTSTRUCT, *PCRYPTPROTECT_PROMPTSTRUCT;

Members

cbSize
The size of the data structure.
dwPromptFlags
DWORD flags that indicate when prompts to the user are to be displayed. Current dwPromptFlags values are:
CRYPTPROTECT_PROMPT_ON_PROTECT
This flag is used to provide the prompt the protect phase.
CRYPTPROTECT_PROMPT_ON_UNPROTECT
This flag may be combined with CRYPTPROTECT_PROMPT_ON_PROTECT to enforce the UI (user interface) policy of the caller. When CryptUnprotectData is called, the dwPromptFlags specified in the CryptProtectData call are enforced.
hwndApp
Window handle to the parent window.
szPrompt
A string containing the text of a prompt to be displayed.

See Also

CryptProtectData, CryptUnprotectData


DHPUBKEY

The DHPUBKEY structure contains information specific to the particular Diffie-Hellman public key contained in the key blob.

typdef struct _PUBKEY {
    DWORD magic;
    DWORD bitlen;
} DHPUBKEY;

Members

magic
This must always be set to "DH1" (0x31484400) when used for public-key blobs and to "DH2" (0x32484400) when used for private-key blobs.

Notice that the hex values are just an ASCII encoding of "DH1" and "DH2."

bitlen
Number of bits in the prime modulus, P.

See Also

BLOBHEADER


DSSPUBKEY

The DSSPUBKEY structure contains information specific to the particular public key contained in the key blob.

typdef struct _PUBKEY {
    DWORD magic;
    DWORD bitlen;
} DSSPUBKEY;

Members

magic
This must always be set to 0x31535344, the ASCII encoding of "DSS1".
bitlen
Number of bits in the DSS key blob's prime, P.

See Also

BLOBHEADER, DSSSEED, RSAPUBKEY


DSSSEED

The DSSSEED structure holds the seed and counter values that may be used to verify the primes of the DSS public key.

typdef struct _DSSSEED {
    DWORD counter;
    BYTE  seed[20];
} DSSSEED;

Members

counter
A DWORD containing the counter value. If the counter value is 0xFFFFFFFF then the seed and counter values are not available.
seed[20]
A BYTE string containing the seed value.

See Also

BLOBHEADER, DSSPUBKEY, RSAPUBKEY


HMAC_INFO

The HMAC_INFO structure is used to specify the hash algorithm, and the inner and outer strings that are to be used in calculating the HMAC hash.

typedef struct _HMAC_Info {
    ALG_ID HashAlgid;
    BYTE *pbInnerString;
    DWORD cbInnerString;
    BYTE *pbOuterString;
    DWORD cbOuterString;
} HMAC_INFO, *PHMAC_INFO;

Members

HashAlgid
Specifies the hash algorithm to be used.
pbInnerString
Pointer to the inner string to be used in the HMAC calculation. The default inner string is defined as the byte 0x36 repeated 64 times.
cbInnerString
The count of bytes in pbInnerString. The CSP will use the default inner string if cbInnerString is equal to zero.
pbOuterString
A pointer to the outer string to be used in the HMAC calculation. The default outer string is defined as the byte 0x5C repeated 64 times.
cbOuterString
The count of bytes in pbOuterString. The CSP will use the default outer string if pbOuterString is equal to zero.

See Also

ALG_ID, HMAC, CryptCreateHash, CryptSetHashParam


RSAPUBKEY

The RSAPUBKEY structure contains information specific to the particular public key contained in the key blob.

typedef struct _RSAPUBKEY {
    DWORD magic;
    DWORD bitlen;
    DWORD pubexp;
} RSAPUBKEY;

Members

magic
This should be set to "RSA1" (0x31415352) for public keys and to "RSA2" (0x32415352) for private keys.

Notice that the hex values are just an ASCII encoding of "RSA1" and "RSA2."

bitlen
Number of bits in the modulus. In practice, this must always be a multiple of eight.
pubexp
The public exponent.

See Also

BLOBHEADER, DSSPUBKEY, DSSSEED


Common Certificate Data Structures

The data structures in this section are used by many of the certificate and simplified message functions.

These structures can be found in Wincrypt.h.


BLOB Structure

The BLOB Structure is used for an array of bytes of arbitrary kind. It provides flexibility for objects that may contain various data types.

typedef struct _CRYPTOAPI_BLOB {
    DWORD    cbData;
    BYTE*    pbData;
} CRYPT_INTEGER_BLOB,    *PCRYPT_INTEGER_BLOB,
    CRYPT_UINT_BLOB,     *PCRYPT_UINT_BLOB,
    CRYPT_OBJID_BLOB,    *PCRYPT_OBJID_BLOB,
    CERT_NAME_BLOB,      *PCERT_NAME_BLOB,
    CERT_RDN_VALUE_BLOB, *PCERT_RDN_VALUE_BLOB,
    CERT_BLOB,           *PCERT_BLOB,
    CRL_BLOB,            *PCRL_BLOB,
    DATA_BLOB,           *PDATA_BLOB,
    CRYPT_DATA_BLOB,     *PCRYPT_DATA_BLOB,
    CRYPT_HASH_BLOB,     *PCRYPT_HASH_BLOB,
    CRYPT_DIGEST_BLOB,   *PCRYPT_DIGEST_BLOB,
    CRYPT_DER_BLOB,      *PCRYPT_DER_BLOB,
    CRYPT_ATTR_BLOB,     *PCRYPT_ATTR_BLOB;

Members

cbData
Count of bytes in the buffer pointed to by pbData.
pbData
Pointer to a block of data bytes.

See Also

CERT_EXTENSION, CERT_POLICY_QUALIFIER_INFO, CERT_REQUEST_INFO, CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA, CMSG_SIGNER_INFO, CRYPT_ATTRIBUTE_TYPE_VALUE, CRYPT_TIME_STAMP_REQUEST_INFO, CertCompareIntegerBlob, CertNameToStr


CERT_CONTEXT

The CERT_CONTEXT structure contains both the encoded and decoded representations of a certificate. A certificate context returned by one of the functions defined in Wincrypt.h must be freed by calling the CertFreeCertificateContext function. The CertDuplicateCertificateContext function can be called to make a duplicate copy (which also must be freed by calling CertFreeCertificateContext).

typedef struct _CERT_CONTEXT {
    DWORD         dwCertEncodingType;
    BYTE*         pbCertEncoded;
    DWORD         cbCertEncoded;
    PCERT_INFO    pCertInfo;
    HCERTSTORE    hCertStore;
} CERT_CONTEXT,  *PCERT_CONTEXT;
typedef const CERT_CONTEXT *PCCERT_CONTEXT;

Members

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbCertEncoded
A pointer to the encoded certificate.
cbCertEncoded
The size, in bytes, of the encoded certificate.
pCertInfo
A pointer to a structure of certificate information.
hCertStore
A handle to the certificate store that contains the certificate context.

See Also

CERT_INFO, CRYPT_SIGN_MESSAGE_PARA, CRYPT_VERIFY_MESSAGE_PARA, CertAddCertificateContextToStore, CertAddEncodedCertificateToStore, CertCreateCertificateContext, CertEnumCertificatesInStore, CertFindCertificateInStore, CertFreeCertificateContext, CertGetIssuerCertificateFromStore, CertGetSubjectCertificateFromStore, CertVerifyRevocation, CryptVerifyMessageSignature


CERT_DSS_PARAMETERS

The CERT_DSS_PARAMETERS structure encoded parameters associated with a DSS public key algorithm.

typedef struct _CERT_DSS_PARAMETERS {
    CRYPT_UINT_BLOB     p;
    CRYPT_UINT_BLOB     q;
    CRYPT_UINT_BLOB     g;
} CERT_DSS_PARAMETERS, *PCERT_DSS_PARAMETERS;

Members

p
The prime modulus P. Must always have the most significant bit of the most significant byte set to 1.
q
The prime Q. It is 20 bytes in length. The Most significant bit of the most significant byte must be set to 1.
g
The generator G. Must be the same length as p (must be padded with 0x00 bytes if it is less).

See Also

The DSS Provider Private-Key Blob


CERT_EXTENSION

The CERT_EXTENSION structure contains the extension information for a certificate. The data in the Value member is in its encoded representation.

typedef struct _CERT_EXTENSION {
    LPSTR              pszObjId;
    BOOL               fCritical;
    CRYPT_OBJID_BLOB   Value;
} CERT_EXTENSION,     *PCERT_EXTENSION;

Members

pszObjId
The object identifier that specifies the type of extension data contained in the Value blob.
fCritical
If this flag is set, the extension must be complied with, or the certificate that contains it should not be used.
Value
A structure that contains the extension data (encoded form).

See Also

BLOB Structure, CERT_EXTENSIONS, CERT_INFO, CRL_ENTRY, CRL_INFO, CertFindExtension


CERT_EXTENSIONS

The CERT_EXTENSIONS structure contains an array of extensions.

typedef struct _CERT_EXTENSIONS {
    DWORD              cExtension;
    PCERT_EXTENSION    rgExtension;
} CERT_EXTENSIONS,    *PCERT_EXTENSIONS;

Members

cExtension
The number of elements in the array rgExtension.
rgExtension
An array of structures, each holding CERT_EXTENSION information about a certificate or CRL.

See Also

CERT_EXTENSION


CERT_INFO

The CERT_INFO structure stores information in a certificate.

typedef struct _CERT_INFO {
    DWORD                       dwVersion;
    CRYPT_INTEGER_BLOB          SerialNumber;
    CRYPT_ALGORITHM_IDENTIFIER  SignatureAlgorithm;
    CERT_NAME_BLOB              Issuer;
    FILETIME                    NotBefore;
    FILETIME                    NotAfter;
    CERT_NAME_BLOB              Subject;
    CERT_PUBLIC_KEY_INFO        SubjectPublicKeyInfo;
    CRYPT_BIT_BLOB              IssuerUniqueId;
    CRYPT_BIT_BLOB              SubjectUniqueId;
    DWORD                       cExtension;
    PCERT_EXTENSION             rgExtension;
} CERT_INFO, *PCERT_INFO;

Members

dwVersion
The certificate's version number. Currently defined version numbers are shown in the following table.
Certificate version name | Value
CERT_V1 | 0
CERT_V2 | 1
CERT_V3 | 2

SerialNumber
The certificate's serial number. (Decoded as a multiple byte integer. SerialNumber.pbData[0] is the least significant byte. SerialNumber.pbData[SerialNumber.cbData - 1] is the most significant byte.)

For X509_ASN_ENCODING, leading 0x00 or 0xFF bytes are removed. See CertCompareIntegerBlob.

SignatureAlgorithm
A structure that contains the signature algorithm type and any associated additional parameters (encoded form).
Issuer
The certificate issuer's name (encoded form).
NotBefore
A date, before which the certificate is not valid. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
NotAfter
A date, after which the certificate is not valid. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
Subject
The certificate subject's name (encoded form).
SubjectPublicKeyInfo
A structure that contains the public key (encoded form) and its algorithm.
IssuerUniqueId
A special designation given to the issuer.
SubjectUniqueId
A special designation given to the subject.
cExtension
The number of elements in the array rgExtension.
rgExtension
An array of structures, each holding CERT_EXTENSION information about the certificate.

See Also

BLOB Structure, CERT_EXTENSION, CERT_PUBLIC_KEY_INFO, CMSG_ENVELOPED_ENCODE_INFO, CMSG_SIGNER_ENCODE_INFO, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_BIT_BLOB, CRYPT_VERIFY_MESSAGE_PARA, CertCompareCertificate, CertGetSubjectCertificateFromStore, CryptMsgControl, CryptMsgGetParam, CryptSignAndEncodeCertificate


CERT_KEY_CONTEXT

The CERT_KEY_CONTEXT structure defines the CERT_KEY_CONTEXT_PROP_ID's pvData.

typedef struct _CERT_KEY_CONTEXT {
    DWORD            cbSize;
    HCRYPTPROV       hCryptProv;
    DWORD            dwKeySpec;
} CERT_KEY_CONTEXT, *PCERT_KEY_CONTEXT;

Members

cbSize
The size of the CERT_KEY_CONTEXT.
hCryptProv
A handle to the cryptographic service provider.
dwKeySpec
The specification of the private key to retrieve.

The following dwKeySpec values are defined in Wincrypt.h for the default provider:

#define AT_KEYEXCHANGE              1
#define AT_SIGNATURE                2

See Also

CertGetCertificateContextProperty, CertSetCertificateContextProperty


CERT_KEYGEN_REQUEST_INFO

The CERT_KEYGEN_REQUEST_INFO structure contains information stored in Netscape's Keygen request. The subject, and subject public key blobs are the encoded representation of the information.

typedef struct _CERT_KEYGEN_REQUEST_INFO {
    DWORD                   dwVersion;
    CERT_PUBLIC_KEY_INFO    SubjectPublicKeyInfo;
    LPWSTR                  pwszChallengeString;   // encoded as IA5
} CERT_KEYGEN_REQUEST_INFO, *PCERT_KEYGEN_REQUEST_INFO;

Members

dwVersion
The certificate's version number. Currently defined version numbers are shown in the following table.
Certificate version name | Value
CERT_V1 | 0

SubjectPublicKeyInfo
A structure that contains the public key (encoded form) and its algorithm.
pwszChallengeString
A random printable string. It is used by the server to insure that the key that it is certifying matches the client on the page.

See Also

CERT_REQUEST_INFO


CERT_NAME_INFO

The CERT_NAME_INFO structure stores information in a subject's or issuer's name. The information is represented as an array of CERT_RDNs.

typedef struct _CERT_NAME_INFO {
    DWORD            cRDN;
    PCERT_RDN        rgRDN;
} CERT_NAME_INFO,   *PCERT_NAME_INFO;

Members

cRDN
The number of elements in the array rgRDN.
rgRDN
An array of structures, each holding CERT_RDN information.

See Also

CERT_RDN, CryptDecodeObject, CryptEncodeObject


CERT_NAME_VALUE

The CERT_NAME_VALUE structure is a CERT_RDN_ATTR without the object identifier. The interpretation of the Value data member depends on the dwValueType.

typedef struct _CERT_NAME_VALUE {
    DWORD                dwValueType;
    CERT_RDN_VALUE_BLOB  Value;
} CERT_NAME_VALUE,      *PCERT_NAME_VALUE;

Members

dwValueType
For CERT_RDN_ENCODED_BLOB, the Value's CERT_RDN_VALUE_BLOB is in its encoded representation. Otherwise, its an array of bytes.

For all CERT_RDN types, Value.cbData is always the number of bytes, not necessarily the number of elements in the string. For instance, CERT_RDN_UNIVERSAL_STRING is an array of ints (cbData == intCnt * 4) and CERT_RDN_BMP_STRING is an array of unsigned shorts (cbData == ushortCnt * 2). The dwValueTypes are defined in Wincrypt.h and are shown in the CERT_RDN_ATTR section.

Value
Either a null-terminated array of 8-bit or 16-bit characters, an array of INT4s, or an encoded representation.

See Also

BLOB Structure


CERT_PHYSICAL_STORE_INFO

The CERT_PHYSICAL_STORE_INFO structure contains the information on physical certificate stores. The Open fields in this structure are passed directly to CertOpenStore to open the physical store.

typedef struct _CERT_PHYSICAL_STORE_INFO{
    DWORD               cbSize;
    LPSTR               pszOpenStoreProvider;
    DWORD               dwOpenEncodingType;
    DWORD               dwOpenFlags;
    CRYPT_DATA_BLOB     OpenParameters;         // REG_BINARY
    DWORD               dwFlags;                // REG_DWORD
    DWORD               dwPriority;             // REG_DWORD
} CERT_PHYSICAL_STORE_INFO, *PCERT_PHYSICAL_STORE_INFO;

Members

cbSize
Set by CertOpenStore to the size of this structure.
pszOpenStoreProvider
See description of store provider in the documentation for CertOpenStore .

Pointer to a string that determines the store provider type. Predefined store provider types are in the documentation for CertOpenStore. Additional store providers may be installed or registered via CryptInstallOIDFunctionAddress or CryptRegisterOIDFunction. For additional information, see Extending CertOpenStore Functionality.

dwOpenEncodingType
This member is applicable only when CERT_STORE_PROV_MSG, CERT_STORE_PROV_PKCS7, or CERT_STORE_PROV_FILENAME is passed in lpszStoreProvider. Otherwise, this member is unused. The LOWORD specifies the encoding type of certificates CRLs, and CTLs. The HIWORD specifies the encoding type of the message.

Both a certificate and a message encoding type are required. They are specified by combining the two encoding types with a bitwise OR operation, as in the following example:

X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

dwOpenFlags
If a system store is opened via the SERVICES or USERS store location, the dwOpenFlags store location is set to CERT_SYSTEM_STORE_USERS or CERT_SYSTEM_STORE_SERVICES.
OpenParameters
If a system store is opened via the SERVICES or USERS store location and the physical store is CERT_SYSTEM_STORE_CURRENT_USER or CERT_SYSTEM_STORE_CURRENT_SERVICE, the ServiceName is placed in front of the OpenParameters.

If a physical store is opened remotely and a SYSTEM, SYSTEM_REGISTRY or PHYSICAL provider type is used, the \\ComputerName is implicitly placed in front of the OpenParameters.

dwFlags
The following dwFlags for CERT_PHYSICAL_STORE_INFO are defined in wincrypt.h:
CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
This flag is to enable the adding of a context to the store.
CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG
This flag is set by CertRegisterPhysicalStore. By default, all system stores located in the registry have an implicit SystemRegistry physical store that is opened. To disable the opening of this store, the SystemRegistry physical store corresponding to the System store must be registered with CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG set or a physical store named ".Default" may be registered with CertRegisterPhysicalStore.
CERT_PHYSICAL_STORE_REMOTE_OPEN_DISABLE_FLAG
When this flag is set, remote opens of the physical store are disabled.
CERT_PHYSICAL_STORE_INSERT_COMPUTER_NAME_ENABLE_FLAG
When this flag is set , a \\ComputerName is placed in front of other provider types.
CERT_SYSTEM_STORE_RELOCATE_FLAG
When this flag is set in the dwFlags member, CertOpenStore can be open a store relative to a user specified HKEY instead of one of the predefined HKEY constants. For example, HKEY_CURRENT_USER can be replaced with a user specified HKEY. When CERT_SYSTEM_STORE_RELOCATE_FLAG is set, the pvPara passed to CertOpenStore points to a CERT_SYSTEM_STORE_RELOCATE_PARA data structure instead of pointing to the store name as a null terminated unicode or ASCII string.
dwPriority
When a system store is opened, its physical stores are ordered according to their dwPriority settings. A higher dwPriority indicates higher priority. dwPriority is passed to CertAddStoreToCollection.


CERT_PUBLIC_KEY_INFO

The CERT_PUBLIC_KEY_INFO structure is a public key and its algorithm.

typedef struct _CERT_PUBLIC_KEY_INFO{
    CRYPT_ALGORITHM_IDENTIFIER  Algorithm;
    CRYPT_BIT_BLOB              PublicKey;
} CERT_PUBLIC_KEY_INFO,        *PCERT_PUBLIC_KEY_INFO;

Members

Algorithm
A structure that contains the public key algorithm type and any associated additional parameters.
PublicKey
A public key (encoded form).

See Also

CERT_INFO, CERT_REQUEST_INFO, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_BIT_BLOB, CertComparePublicKeyInfo, CertFindCertificateInStore, CryptImportPublicKeyInfoEx


CERT_REQUEST_INFO

The CERT_REQUEST_INFO structure stores information in a certificate request. The subject, subject public key, and attribute blobs are the encoded representation of the information.

typedef struct _CERT_REQUEST_INFO {
    DWORD                 dwVersion;
    CERT_NAME_BLOB        Subject;
    CERT_PUBLIC_KEY_INFO  SubjectPublicKeyInfo;
    DWORD                 cAttribute;
    PCRYPT_ATTRIBUTE      rgAttribute;
} CERT_REQUEST_INFO,     *PCERT_REQUEST_INFO;

Members

dwVersion
The certificate's version number. Currently defined version numbers are shown in the following table.
Certificate version name | Value
CERT_V1 | 0

Subject
The certificate subject's name (encoded form).
SubjectPublicKeyInfo
A structure that contains the public key (encoded form) and its algorithm.
cAttribute
The number of elements in the array rgAttribute.
rgAttribute
An array of structures, each holding CRYPT_ATTRIBUTE information about the certificate.

See Also

BLOB Structure, CERT_PUBLIC_KEY_INFO, CRYPT_ATTRIBUTE, CryptSignAndEncodeCertificate


CERT_RDN

The CERT_RDN structure is a Relative Distinguished Name (RDN) which consists of an array of CERT_RDN_ATTR structures.

typedef struct _CERT_RDN {
    DWORD            cRDNAttr;
    PCERT_RDN_ATTR   rgRDNAttr;
} CERT_RDN,         *PCERT_RDN;

Members

cRDNAttr
The number of elements in the array rgRDNAttr.
rgRDNAttr
An array of CERT_RDN_ATTR structures.

See Also

CERT_NAME_INFO, CERT_RDN_ATTR, CertFindCertificateInStore, CertIsRDNAttrsInCertificateName, CertNameToStr


CERT_RDN_ATTR

The CERT_RDN_ATTR structure are attributes that make up a Relative Distinguished Name (RDN). The interpretation of the data member Value depends on the dwValueType.

typedef struct _CERT_RDN_ATTR {
    LPSTR                  pszObjId;
    DWORD                  dwValueType;
    CERT_RDN_VALUE_BLOB    Value;
} CERT_RDN_ATTR,          *PCERT_RDN_ATTR;

Members

pszObjId
Currently defined CERT_RDN attribute object identifiers are shown in the following table.
CERT_RDN attribute object identifier | Value | Comments
// Labeling attribute types:
szOID_COMMON_NAME | "2.5.4.3" | case-ignore string
szOID_SUR_NAME | "2.5.4.4" | case-ignore string
szOID_DEVICE_SERIAL_NUMBER | "2.5.4.5" | printable string
// Geographic attribute types:
szOID_COUNTRY_NAME | "2.5.4.6" | printable 2char string
szOID_LOCALITY_NAME | "2.5.4.7" | case-ignore string
szOID_STATE_OR_PROVINCE_NAME | "2.5.4.8" | case-ignore string
szOID_STREET_ADDRESS | "2.5.4.9" | case-ignore string
// Organizational attribute types:
szOID_ORGANIZATION_NAME | "2.5.4.10" | case-ignore string
szOID_ORGANIZATIONAL_UNIT_NAME | "2.5.4.11" | case-ignore string
szOID_TITLE | "2.5.4.12" | case-ignore string
// Explanatory attribute types:
szOID_DESCRIPTION | "2.5.4.13" | case-ignore string
szOID_SEARCH_GUIDE | "2.5.4.14"
szOID_BUSINESS_CATEGORY | "2.5.4.15" | case-ignore string
// Postal addressing attribute types:
szOID_POSTAL_ADDRESS | "2.5.4.16"
szOID_POSTAL_CODE | "2.5.4.17" | case-ignore string
szOID_POST_OFFICE_BOX | "2.5.4.18" | case-ignore string
szOID_PHYSICAL_DELIVERY_OFFICE_NAME | "2.5.4.19" | case-ignore string
// Telecommunications addressing attribute types:
szOID_TELEPHONE_NUMBER | "2.5.4.20" | telephone number
szOID_TELEX_NUMBER | "2.5.4.21"
szOID_TELETEXT_TERMINAL_IDENTIFIER | "2.5.4.22"
szOID_FACSIMILE_TELEPHONE_NUMBER | "2.5.4.23"
szOID_X21_ADDRESS | "2.5.4.24" | numeric string
szOID_INTERNATIONAL_ISDN_NUMBER | "2.5.4.25" | numeric string
szOID_REGISTERED_ADDRESS | "2.5.4.26"
szOID_DESTINATION_INDICATOR | "2.5.4.27" | printable string
// Preference attribute types:
szOID_PREFERRED_DELIVERY_METHOD | "2.5.4.28"
// OSI application attribute types:
szOID_PRESENTATION_ADDRESS | "2.5.4.29"
szOID_SUPPORTED_APPLICATION_CONTEXT | "2.5.4.30"
// Relational application attribute types:
szOID_MEMBER | "2.5.4.31"
szOID_OWNER | "2.5.4.32"
szOID_ROLE_OCCUPANT | "2.5.4.33"
szOID_SEE_ALSO | "2.5.4.34"
// Security attribute types:
szOID_USER_PASSWORD | "2.5.4.35"
szOID_USER_CERTIFICATE | "2.5.4.36"
szOID_CA_CERTIFICATE | "2.5.4.37"
szOID_AUTHORITY_REVOCATION_LIST | "2.5.4.38"
szOID_CERTIFICATE_REVOCATION_LIST | "2.5.4.39"
szOID_CROSS_CERTIFICATE_PAIR | "2.5.4.40"
// Name attribute types:
szOID_GIVEN_NAME | "2.5.4.42" | case-ignore string
szOID_INITIALS | "2.5.4.43" | case-ignore string
// Email:
szOID_RSA_emailAddr "1.2.840.
113549.1.
9.1" 		IA5 string
szOID_DOMAIN_COMPONENT "0.9.2342.
19200300.
100.1.25" 		IA5 string
//Pilot user attribute types:
szOID_DOMAIN_COMPONENT "0.9.2342.
19200300.
100.1.25" 		IA5 string
//Used for PKCS 12 attributes
szOID_PKCS_12_FRIENDLY_NAME_ATTR "1.2.840.
113549.1.
9.20"
szOID_PKCS_12_LOCAL_KEY_ID "1.2.840.
113549.1.
9.21"

dwValueType
For CERT_RDN_ENCODED_BLOB, the Value's CERT_RDN_VALUE_BLOB is in its encoded representation. Otherwise, it's an array of bytes.

For all CERT_RDN types, Value.cbData is always the number of bytes, not necessarily the number of elements in the string. For instance, CERT_RDN_UNIVERSAL_STRING is an array of ints (cbData == intCnt * 4) and CERT_RDN_BMP_STRING is an array of unsigned
shorts (cbData == ushortCnt * 2).

The following dwValueTypes are defined in Wincrypt.h:

#define CERT_RDN_ANY_TYPE                    0
#define CERT_RDN_ENCODED_BLOB                1
#define CERT_RDN_OCTET_STRING                2
#define CERT_RDN_NUMERIC_STRING              3
#define CERT_RDN_PRINTABLE_STRING            4
#define CERT_RDN_TELETEX_STRING              5
#define CERT_RDN_T61_STRING                  5
#define CERT_RDN_VIDEOTEX_STRING             6
#define CERT_RDN_IA5_STRING                  7
#define CERT_RDN_GRAPHIC_STRING              8
#define CERT_RDN_VISIBLE_STRING              9
#define CERT_RDN_ISO646_STRING               9
#define CERT_RDN_GENERAL_STRING              10
#define CERT_RDN_UNIVERSAL_STRING            11
#define CERT_RDN_INT4_STRING                 11
#define CERT_RDN_BMP_STRING                  12
#define CERT_RDN_UNICODE_STRING              12

#define CERT_RDN_TYPE_MASK                  0x000000FF
#define CERT_RDN_FLAGS_MASK .........       0xff000000
#define CERT_RDN_ENABLE_T61_UNICODE_FLAG    0x80000000
#define CERT_RDN_DISABLE_CHECK_TYPE_FLAG    0x40000000
#define CERT_RDN_DISABLE_IE4_UTF8_FLAG      0x01000000

The following table describes the type of content that corresponds to various dwValueTypes.
dwValueType | Value/ description
CERT_RDN_OCTET_STRING | An arbitrary string of octets (8-bit)
CERT_RDN_NUMERIC_STRING | Only the characters 0 through 9, and the space character (8-bit)
CERT_RDN_PRINTABLE_STRING | An arbitrary string of printable characters (8-bit)
CERT_RDN_TELETEX_STRING | An arbitrary string of T.61 (8-bit) characters
CERT_RDN_T61_STRING | An arbitrary string of T.61 (8-bit) characters
CERT_RDN_VIDEOTEX_STRING | An arbitrary string of VIDEOTEX characters
CERT_RDN_IA5_STRING | An arbitrary string of IA5 (ASCII) characters
CERT_RDN_VISIBLE_STRING | A 95-character set (8-bit)
CERT_RDN_ISO646_STRING | A 128-character set (8-bit)
CERT_RDN_UNIVERSAL_STRING | An array of INT4s (32-bit)
CERT_RDN_INT4_STRING | An array of INT4s (32-bit)
CERT_RDN_BMP_STRING | An array of Unicode characters (16-bit)
CERT_RDN_UNICODE_STRING | An array of Unicode characters (16-bit)

The following flags can be combined with a bitwise OR operation into CERT_RDN_ATTR data structure's dwValueType.

dwValueType | Value/ description
CERT_RDN_ENABLE_T61_ UNICODE_FLAG | For encoding. When set, if all the UNICODE characters are <= 0xFF, the CERT_RDN_T61_STRING is selected instead of the CERT_ RDN_UNICODE_STRING.
CERT_RDN_DISABLE_CHECK_ TYPE_FLAG | For encoding. When set, the characters are not checked to see if they are valid for the Value Type.
CERT_RDN_DISABLE_IE4_ UTF8_FLAG | For decoding. By default, CERT_RDN_T61_STRING encoded values are initially decoded as UTF8. If the UTF8 decoding fails, then the value is decoded as 8 bit characters. If this flag is set, it skips the initial attempt to decode as UTF8 and decodes the value as 8 bit characters.

Value
Either a null-terminated array of 8-bit or 16-bit characters, an array of INT4s, or an encoded representation.

See Also

BLOB Structure, CERT_RDN, CertIsRDNAttrsInCertificateName


CERT_REVOCATION_PARA

The CERT_REVOCATION_PARA structure may optionally be passed to CertVerifyRevocation to assist in finding the issuer of the context to be verified.

typedef struct _CERT_REVOCATION_PARA {
    DWORD                   cbSize;
    PCCERT_CONTEXT          pIssuerCert;
    DWORD                   cCertStore;
    HCERTSTORE              *rgCertStore;
} CERT_REVOCATION_PARA, *PCERT_REVOCATION_PARA;

Members

cbSize
The count of bytes in this data structure.
pIssuerCert
When specified, pIssuerCert is the issuer of rgpvContext[cContext - 1] (in the CertVerifyRevocation parameter list).
cCertStore
The number of elements in the array rgCertStore.
rgCertStore
An array of certificate store handles. When rgCertStore is used, these stores may contain an issuer certificate.

See Also

CertVerifyRevocation


CERT_REVOCATION_STATUS

The CERT_REVOCATION_STATUS structure is returned by CertVerifyRevocation to specify the status of the revoked or unchecked context. See CertVerifyRevocation for details.

typedef struct _CERT_REVOCATION_STATUS {
    DWORD                   cbSize;
    DWORD                   dwIndex;
    DWORD                   dwError;
    DWORD                   dwReason;
} CERT_REVOCATION_STATUS, *PCERT_REVOCATION_STATUS;

Members

cbSize
The count of bytes in this data structure.

Upon input to CertVerifyRevocation, cbSize must be set to a size >= sizeof(CERT_REVOCATION_STATUS). Otherwise, CertVerifyRevocation returns FALSE and sets LastError to E_INVALIDARG.

dwIndex
Upon return from CertVerifyRevocation, dwIndex specifies the index of the first context that was revoked or unable to be checked for revocation. If the caller wants more information about the remaining contexts that have not been checked, CertVerifyRevocation will need to be called again, specifying a list in rgpvContext[] that contains the unchecked contexts from the original list.
dwError
Upon return from CertVerifyRevocation, dwError specifies the error status. LastError as reported from CertVerifyRevocation is also set to this error status. See the table in the "Return Values" section in CertVerifyRevocation for the list of error values.
dwReason
Upon return from CertVerifyRevocation, dwReason specifies the reason for the error. dwReason is currently only set when dwError equals CRYPT_E_REVOKED and contains the reason why the context was revoked. It may be one of the following:
CRL_REASON_UNSPECIFIED 0
No reason was specified for why the certificate was revoked.
CRL_REASON_KEY_COMPROMISE 1
Used in revocation of an end entity certificate. It indicates that it is known or suspected that the subject's private key, or other aspects of the subject validated in the certificate, have been compromised.
CRL_REASON_CA_COMPROMISE 2
Used in revocation of a CA-certificate. It indicates that it is known or suspected that the subject's private key, or other aspects of the subject validated in the certificate, have been compromised.
CRL_REASON_AFFILIATION_CHANGED 3
Indicates that the subject's name or other information in the certificate has been modified but there is no cause to suspect that the private key has been compromised.
CRL_REASON_SUPERSEDED 4
Indicates that the certificate has been superseded, but there is no cause to suspect that the private key has been compromised.
CRL_REASON_CESSATION_OF_OPERATION 5
Indicates that the certificate is no longer needed for the purpose of which it was issued, but there is no cause to suspect that the private key has been compromised.
CRL_REASON_CERTIFICATE_HOLD 6
Indicates that the certificate has been placed on hold.

See Also

CertVerifyRevocation


CERT_SIGNED_CONTENT_INFO

The CERT_SIGNED_CONTENT_INFO structure is a "to be signed" encoded content and its signature. The ToBeSigned member is the encoded CERT_INFO, CRL_INFO, or CERT_REQUEST_INFO.

typedef struct _CERT_SIGNED_CONTENT_INFO {
    CRYPT_DER_BLOB               ToBeSigned;
    CRYPT_ALGORITHM_IDENTIFIER   SignatureAlgorithm;
    CRYPT_BIT_BLOB               Signature;
} CERT_SIGNED_CONTENT_INFO,     *PCERT_SIGNED_CONTENT_INFO;

Members

ToBeSigned
A DER-encoded blob that is to be signed.
SignatureAlgorithm
A structure that contains the signature algorithm type and any associated additional parameters (encoded form).
Signature
The signed hash of the ToBeSigned member.

See Also

BLOB Structure, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_BIT_BLOB


CERT_SYSTEM_STORE_INFO

The CERT_SYSTEM_STORE_INFO data structures contain information used by functions that work with system stores. Currently, no essential information is contain in this structure.

typedef struct _CERT_SYSTEM_STORE_INFO {
  DWORD               cbSize;
  } CERT_SYSTEM_STORE_INFO, *PCERT_SYSTEM_STORE_INFO;

Members

cbSize
Set by CertOpenStore to the size of this structure.

Remarks

Currently, no system store information is persisted.


CERT_SYSTEM_STORE_RELOCATE_PARA

The CERT_SYSTEM_STORE_RELOCATE_PARA data structure is passed to CertOpenStore when the CERT_SYSTEM_STORE_RELOCATE_FLAG is set. It allows the application to pass in not only a string indicating the name of the store to be opened, but also registry hKey information indicating a registry location other than the default location.

typedef struct _CERT_SYSTEM_STORE_RELOCATE_PARA {
    union {
        HKEY                hKeyBase;
        void                *pvBase;
    };
    union {
        void                *pvSystemStore;
        LPCSTR              pszSystemStore;
        LPCWSTR             pwszSystemStore;
    };
} CERT_SYSTEM_STORE_RELOCATE_PARA, *PCERT_SYSTEM_STORE_RELOCATE_PARA;

Members

hKeyBase
Registry hKey handle.
pvBase
Pointer to a void to allow the system store location's base to be passed in a number of different forms.
pvSystemStore
Pointer to a void to allow the name of the system store to be passed in various forms.
pszSystemStore
NULL terminated ASCII string naming of the system store.
pwszSystemStore
NULL terminated unicode string naming of the system store.

Remarks

The relocate capability is used to access system stores persisted in the Group Policy Template (GPT). For example, the Group Policy Editor's (GPE) MMC snap-in extension for managing group policy trust lists and certificates will call CertOpenStore using the GPT's base HKEY.


CRL_CONTEXT

The CRL_CONTEXT structure is a Certificate Revocation List (CRL) context structure which contains both the encoded and decoded representations of a CRL. A CRL context returned by a certificate store function must be freed by calling the CertFreeCRLContext function. The CertDuplicateCRLContext function can be called to make a duplicate copy (which also must be freed by calling CertFreeCRLContext).

typedef struct _CRL_CONTEXT {
    DWORD           dwCertEncodingType;
    BYTE*           pbCrlEncoded;
    DWORD           cbCrlEncoded;
    PCRL_INFO       pCrlInfo;
    HCERTSTORE      hCertStore;
} CRL_CONTEXT,     *PCRL_CONTEXT;
typedef const CRL_CONTEXT *PCCRL_CONTEXT;

Members

dwCertEncodingType
The type of encoding used on the certificate. Currently defined certificate encoding types are shown in the following table:
Encoding type | Value
X509_ASN_ENCODING | 0x00000001

pbCrlEncoded
A pointer to the encoded CRL.
cbCrlEncoded
The size, in bytes, of the encoded CRL.
pCrlInfo
A pointer to a structure of CRL information.
hCertStore
A handle to the certificate store.

See Also

CRL_INFO, CRYPT_SIGN_MESSAGE_PARA, CertAddCRLContextToStore, CertAddEncodedCRLToStore, CertCreateCRLContext, CertFreeCRLContext, CertGetCRLFromStore


CRL_ENTRY

The CRL_ENTRY structure is an entry in a CRL.

typedef struct _ CRL_ENTRY {
    CRYPT_INTEGER_BLOB    SerialNumber;
    FILETIME              RevocationDate;
    DWORD                 cExtension;
    PCERT_EXTENSION       rgExtension;
} CRL_ENTRY,             *PCRL_ENTRY;

Members

SerialNumber
The serial number of a certificate that was revoked. See CERT_INFO for details.

For X509_ASN_ENCODING, leading 0x00 or 0xFF bytes are removed. See CertCompareIntegerBlob.

RevocationDate
The date that the certificate was revoked. For X509_ASN_ENCODING, time is encoded as a two-digit year precise to seconds. The two-digit year is interpreted as being the four-digit years of 1968 through 2067.
cExtension
The number of elements in the array rgExtension.
rgExtension
An array of structures, each holding CERT_EXTENSION information about the revoked certificate.

See Also

BLOB Structure, CERT_EXTENSION, CRL_INFO


CRL_INFO

The CRL_INFO structure stores information in a CRL.

typedef struct _CRL_INFO {
    DWORD                        dwVersion;
    CRYPT_ALGORITHM_IDENTIFIER   SignatureAlgorithm;
    CERT_NAME_BLOB               Issuer;
    FILETIME                     ThisUpdate;
    FILETIME                     NextUpdate;
    DWORD                        cCRLEntry;
    PCRL_ENTRY                   rgCRLEntry;
    DWORD                        cExtension;
    PCERT_EXTENSION              rgExtension;
} CRL_INFO,                     *PCRL_INFO;

Members

dwVersion
The CRL's version number. Currently defined version numbers are shown in the following table.
Certificate version name | Value
CRL_V1 | 0
CRL_V2 | 1

SignatureAlgorithm
A structure that contains the signature algorithm type and any associated additional parameters (encoded form).
Issuer
The certificate issuer's name (encoded form).
ThisUpdate
Indicates when a CRL was published. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
NextUpdate
Indicates when the next update of a CRL is scheduled to be available. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
cCRLEntry
The number of elements in the array rgCRLEntry.
rgCRLEntry
An array of structures, each holding CRL_ENTRY information.
cExtension
The number of elements in the array rgExtension.
rgExtension
An array of structures, each holding CERT_EXTENSION information about the CRL.

See Also

BLOB Structure, CERT_EXTENSION, CRL_ENTRY, CRYPT_ALGORITHM_IDENTIFIER, CertVerifyCRLRevocation, CryptSignAndEncodeCertificate


CRYPT_ALGORITHM_IDENTIFIER

The CRYPT_ALGORITHM_IDENTIFIER structure is used to describe any algorithm, where the parameters contained in a CRYPT_OBJID_BLOB are in their encoded representation. For most algorithm types, there are no parameters (Parameters.cbData == 0), and those that do have parameters are listed under the Parameters member.

typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
    LPSTR                          pszObjId;
    CRYPT_OBJID_BLOB               Parameters;
} CRYPT_ALGORITHM_IDENTIFIER,     *PCRYPT_ALGORITHM_IDENTIFIER;

Members

pszObjId
The following are the definitions of various algorithm object identifiers, and can also be found in Wincrypt.h:
Name | Base/Suffix | Value
//RSA
szOID_RSA | "1.2.840.113549"
szOID_PKCS | szOID_RSA ".1" | "1.2.840.113549.1"
szOID_RSA_HASH | szOID_RSA ".2" | "1.2.840.113549.2"
szOID_RSA_ENCRYPT | szOID_RSA ".3" | "1.2.840.113549.3"
szOID_PKCS_1 | szOID_PKCS ".1" | "1.2.840.113549.1.1"
szOID_PKCS_2 | szOID_PKCS ".2" | "1.2.840.113549.1.2"
szOID_PKCS_3 | szOID_PKCS ".3" | "1.2.840.113549.1.3"
szOID_PKCS_4 | szOID_PKCS ".4" | "1.2.840.113549.1.4"
szOID_PKCS_5 | szOID_PKCS ".5" | "1.2.840.113549.1.5"
szOID_PKCS_6 | szOID_PKCS ".7" | "1.2.840.113549.1.6"
szOID_PKCS_7 | szOID_PKCS ".7" | "1.2.840.113549.1.7"
szOID_PKCS_8 | szOID_PKCS ".8" | "1.2.840.113549.1.8"
szOID_PKCS_9 | szOID_PKCS ".9" | "1.2.840.113549.1.9"
szOID_PKCS_10 | szOID_PKCS ".10" | "1.2.840.113549.1.10"
szOID_PKCS_12 | szOID_PKCS ".12" | "1.2.840.113549.1.12"
szOID_RSA_MD2 | szOID_RSA_HASH ".2" | "1.2.840.113549.2.2"
szOID_RSA_MD4 | szOID_RSA_HASH ".4" | "1.2.840.113549.2.4"
szOID_RSA_MD5 | szOID_RSA_HASH ".5" | "1.2.840.113549.2.5"
szOID_RSA_RSA | szOID_PKCS_1 ".1" | "1.2.840.113549.1.1.1"
szOID_RSA_MD2RSA | szOID_PKCS_1 ".2" | "1.2.840.113549.1.1.2"
szOID_RSA_MD4RSA | szOID_PKCS_1 ".3" | "1.2.840.113549.1.1.3"
szOID_RSA_MD5RSA | szOID_PKCS_1 ".4" | "1.2.840.113549.1.1.4"

// The following two are per Bob Baldwin (baldwin@rsa.com, 5.7.96)
Name | Base/Suffix | Value
szOID_RSA_SHA1RSA | szOID_PKCS_1 ".5" | "1.2.840.113549.1.1.5"
szOID_RSA_SETOAEP_RSA | szOID_PKCS_1 ".6" | "1.2.840.113549.1.1.6"
szOID_RSA_DH | szOID_PKCS_3 ".1" | "1.2.840.113549.1.3.1
szOID_RSA_data | szOID_PKCS_7 ".1" | "1.2.840.113549.1.7.1"
szOID_RSA_signedData | szOID_PKCS_7 ".2" | "1.2.840.113549.1.7.2"
szOID_RSA_envelopedData | szOID_PKCS_7 ".3" | "1.2.840.113549.1.7.3"
szOID_RSA_signEnvData | szOID_PKCS_7 ".4" | "1.2.840.113549.1.7.4"
szOID_RSA_digestedData | szOID_PKCS_7 ".5" | "1.2.840.113549.1.7.5"
szOID_RSA_hashedData | szOID_PKCS_7 ".5" | "1.2.840.113549.1.7.5"
szOID_RSA_encryptedData | szOID_PKCS_7 ".6" | "1.2.840.113549.1.7.6"
szOID_RSA_emailAddr | szOID_PKCS_9 ".1" | "1.2.840.113549.1.9.1"
szOID_RSA_unstructName | szOID_PKCS_9 ".2" | "1.2.840.113549.1.9.2"
szOID_RSA_contentType | szOID_PKCS_9 ".3" | "1.2.840.113549.1.9.3"
szOID_RSA_messageDigest | szOID_PKCS_9 ".4" | "1.2.840.113549.1.9.4"
szOID_RSA_signingTime | szOID_PKCS_9 ".5" | "1.2.840.113549.1.9.5"
szOID_RSA_counterSign | szOID_PKCS_9 ".6" | "1.2.840.113549.1.9.6"
szOID_RSA_challengePwd | szOID_PKCS_9 ".7" | "1.2.840.113549.1.9.7"
szOID_RSA_unstructAddr | szOID_PKCS_9 ".8" | "1.2.840.113549.1.9.8"
szOID_RSA_extCertAttrs | szOID_PKCS_9 ".9" | "1.2.840.113549.1.9.9"
szOID_RSA_SMIMECapabilities | szOID_PKCS_9 ".15" | "1.2.840.113549.1.9.15"
szOID_RSA_preferSignedData | szOID_RSA_SMIMECapabilities | "1.2.840.113549.1.9.15.1"
szOID_RSA_RC2CBC | szOID_RSA_ENCRYPT ".2" | "1.2.840.113549.3.2"
szOID_RSA_RC4 | szOID_RSA_ENCRYPT ".4" | "1.2.840.113549.3.4"
szOID_RSA_DES_EDE3_CBC | szOID_RSA_ENCRYPT ".7" | "1.2.840.113549.3.7"
szOID_RSA_RC5_CBCPad | szOID_RSA_ENCRYPT ".9" | "1.2.840.113549.3.9"
szOID_ANSI_x942 | "1.2.840.10046"
szOID_ANSI_x942_DH | szOID_ANSI_x942 ".2.1" | "1.2.840.10046.2.1"
szOID_X957 | "1.2.840.10040"
szOID_X957_DSA | szOID_x957 ".4.1" | "1.2.840.10040.4.1"
//ITU-T Useful Definitions
szOID_DS | "2.5"
szOID_DSALG | szOID_DS ".8" | "2.5.8"
szOID_DSALG_CRPT | szOID_DSALG ".1" | "2.5.8.1"
szOID_DSALG_HASH | szOID_DSALG ".2" | "2.5.8.2"
szOID_DSALG_SIGN | szOID_DSALG ".3" | "2.5.8.3"
szOID_DSALG_RSA | szOID_DSALG_CRPT ".1" | "2.5.8.1.1"

//NIST OSE Implementers' Workshop (OIW)
//http://nemo.ncsl.nist.gov/oiw/agreements/stable/OSI/12s_9506.w51
//http://nemo.ncsl.nist.gov/oiw/agreements/working/OSI/12w_9503.w51
szOID_OIW | "1.3.14"

//NIST OSE Implementers' Workshop (OIW) Security SIG algorithm //identifiers
Name | Base/Suffix | Value
szOID_OIWSEC | szOID_OIW ".3.2" | "1.3.14.3.2"
szOID_OIWSEC_md4RSA | szOID_OIWSEC ".2" | "1.3.14.3.2.2"
szOID_OIWSEC_md5RSA | szOID_OIWSEC ".3" | "1.3.14.3.2.3"
szOID_OIWSEC_md4RSA2 | szOID_OIWSEC ".4" | "1.3.14.3.2.4"
szOID_OIWSEC_desECB | szOID_OIWSEC ".6" | "1.3.14.3.2.6"
szOID_OIWSEC_desCBC | szOID_OIWSEC ".7" | "1.3.14.3.2.7"
szOID_OIWSEC_desOFB | szOID_OIWSEC ".8" | "1.3.14.3.2.8"
szOID_OIWSEC_desCFB | szOID_OIWSEC ".9" | "1.3.14.3.2.9"
szOID_OIWSEC_desMAC | szOID_OIWSEC ".10" | "1.3.14.3.2.10"
szOID_OIWSEC_rsaSign | szOID_OIWSEC ".11" | "1.3.14.3.2.11"
szOID_OIWSEC_dsa | szOID_OIWSEC ".12" | "1.3.14.3.2.12"
szOID_OIWSEC_shaDSA | szOID_OIWSEC ".13" | "1.3.14.3.2.13"
szOID_OIWSEC_mdc2RSA | szOID_OIWSEC ".14" | "1.3.14.3.2.14"
szOID_OIWSEC_shaRSA | szOID_OIWSEC ".15" | "1.3.14.3.2.15"
szOID_OIWSEC_dhCommMod | szOID_OIWSEC ".16" | "1.3.14.3.2.16"
szOID_OIWSEC_desEDE | szOID_OIWSEC ".17" | "1.3.14.3.2.17"
szOID_OIWSEC_sha | szOID_OIWSEC ".18" | "1.3.14.3.2.18"
szOID_OIWSEC_mdc2 | szOID_OIWSEC ".19" | "1.3.14.3.2.19"
szOID_OIWSEC_dsaComm | szOID_OIWSEC ".20" | "1.3.14.3.2.20"
szOID_OIWSEC_dsaCommSHA | szOID_OIWSEC ".21" | "1.3.14.3.2.21"
szOID_OIWSEC_rsaXchg | szOID_OIWSEC ".22" | "1.3.14.3.2.22"
szOID_OIWSEC_keyHashSeal | szOID_OIWSEC ".23" | "1.3.14.3.2.23"
szOID_OIWSEC_md2RSASign | szOID_OIWSEC ".24" | "1.3.14.3.2.24"
szOID_OIWSEC_md5RSASign | szOID_OIWSEC ".25" | "1.3.14.3.2.25"
szOID_OIWSEC_sha1 | szOID_OIWSEC ".26" | "1.3.14.3.2.26"
szOID_OIWSEC_dsaSHA1 | szOID_OIWSEC ".27" | "1.3.14.3.2.27"
szOID_OIWSEC_dsaCommSHA1 | szOID_OIWSEC ".28" | "1.3.14.3.2.28"
szOID_OIWSEC_sha1RSASign | szOID_OIWSEC ".29" | "1.3.14.3.2.29"

//NIST OSE Implementers' Workshop (OIW) Directory SIG algorithm //identifiers
Name | Base/Suffix | Value
szOID_OIWDIR | szOID_OIW ".7.2" | "1.3.14.7.2"
szOID_OIWDIR_CRPT | szOID_OIWDIR ".1" | "1.3.14.7.2.1"
szOID_OIWDIR_HASH | szOID_OIWDIR ".2" | "1.3.14.7.2.2"
szOID_OIWDIR_SIGN | szOID_OIWDIR ".3" | "1.3.14.7.2.3"
szOID_OIWDIR_md2 | szOID_OIWDIR_HASH ".1" | "1.3.14.7.2.2.1"
szOID_OIWDIR_md2RSA | szOID_OIWDIR_SIGN ".1" | "1.3.14.7.2.3.1"

//INFOSEC Algorithms
joint-iso-ccitt(2) country(16) us(840) organization(1) us-government(101) dod(2) id-infosec(1)
Name | Base/Suffix | Value
szOID_INFOSEC | "2.16.840.1.101.2.1"
szOID_INFOSEC_sdnsSignature | szOID_INFOSEC".1.1" | "2.16.840.1.101.2.1.1.1"
szOID_INFOSEC_mosaicSignature | szOID_INFOSEC".1.2" | "2.16.840.1.101.2.1.1.2"
szOID_INFOSEC_sdnsConfidentiality | szOID_INFOSEC".1.3" | "2.16.840.1.101.2.1.1.3"
szOID_INFOSEC_mosaicConfidentiality | szOID_INFOSEC".1.4" | "2.16.840.1.101.2.1.1.4"
szOID_INFOSEC_sdnsIntegrity | szOID_INFOSEC".1.5" | "2.16.840.1.101.2.1.1.5"
szOID_INFOSEC_mosaicIntegrity | szOID_INFOSEC".1.6" | "2.16.840.1.101.2.1.1.6"
szOID_INFOSEC_sdnsTokenProtection | szOID_INFOSEC".1.7" | "2.16.840.1.101.2.1.1.7"
szOID_INFOSEC_mosaicTokenProtection | szOID_INFOSEC".1.8" | "2.16.840.1.101.2.1.1.8"
szOID_INFOSEC_sdnsKeyManagement | szOID_INFOSEC".1.9" | "2.16.840.1.101.2.1.1.9"
szOID_INFOSEC_mosaicKeyManagement | szOID_INFOSEC".1.10" | "2.16.840.1.101.2.1.1.10"
szOID_INFOSEC_sdnsKMandSig | szOID_INFOSEC".1.11" | "2.16.840.1.101.2.1.1.11"
szOID_INFOSEC_mosaicKMandSig | szOID_INFOSEC".1.12" | "2.16.840.1.101.2.1.1.12"
szOID_INFOSEC_SuiteASignature | szOID_INFOSEC".1.13" | "2.16.840.1.101.2.1.1.13"
szOID_INFOSEC_SuiteAConfidentiality | szOID_INFOSEC".1.14" | "2.16.840.1.101.2.1.1.14"
szOID_INFOSEC_SuiteAIntegrity | szOID_INFOSEC".1.15" | "2.16.840.1.101.2.1.1.15"
szOID_INFOSEC_SuiteATokenProtection | szOID_INFOSEC".1.16" | "2.16.840.1.101.2.1.1.16"
szOID_INFOSEC_SuiteAKeyManagement | szOID_INFOSEC".1.17" | "2.16.840.1.101.2.1.1.17"
szOID_INFOSEC_SuiteAKMandSig | szOID_INFOSEC".1.18" | "2.16.840.1.101.2.1.1.18"
szOID_INFOSEC_mosaicUpdatedSig | szOID_INFOSEC".1.19" | "2.16.840.1.101.2.1.1.19"
szOID_INFOSEC_mosaicKMandUpdSig | szOID_INFOSEC".1.20" | "2.16.840.1.101.2.1.1.20"
szOID_INFOSEC_mosaicUpdatedInteg | szOID_INFOSEC".1.21" | "2.16.840.1.101.2.1.1.21"

Parameters
An algorithm-specific encoded value. In the normal case there are no parameters (indicated by Parameters.cbData == 0).

The following algorithms have encoded parameters. See the predefined constants for encode/decode details.
Algorithm name | Predefined constant
szOID_OIWSEC_dsa | X509_DSS_PARAMETERS
szOID_RSA_RC2CBC | PKCS_RC2_CBC_PARAMETERS
szOID_OIWSEC_desCBC | X509_OCTET_STRING
szOID_RSA_DES_EDE3_CBC | X509_OCTET_STRING
szOID_RSA_RC4 | X509_OCTET_STRING

See Also

ALG_ID, BLOB Structure, CERT_INFO, CERT_PUBLIC_KEY_INFO, CERT_SIGNED_CONTENT_INFO, CMSG_ENVELOPED_ENCODE_INFO, CMSG_HASHED_ENCODE_INFO, CMSG_SIGNER_ENCODE_INFO, CMSG_SIGNER_INFO, CRL_INFO, CRYPT_ENCRYPT_MESSAGE_PARA, CRYPT_HASH_MESSAGE_PARA, CRYPT_SIGN_MESSAGE_PARA, CryptMsgGetParam


CRYPT_ATTRIBUTE

The CRYPT_ATTRIBUTE structure is used to specify an attribute having one or more values.

typedef struct _CRYPT_ATTRIBUTE {
    LPSTR            pszObjId;
    DWORD            cValue;
    PCRYPT_ATTR_BLOB rgValue;
} CRYPT_ATTRIBUTE,  *PCRYPT_ATTRIBUTE;

Members

pszObjId
The object identifier that specifies the type of attribute data contained in the rgValue array.
cValue
The number of elements in the array rgValue.
rgValue
An array of CRYPT_ATTR_BLOB structures.

See Also

BLOB Structure, CERT_REQUEST_INFO, CMSG_SIGNER_ENCODE_INFO, CRYPT_ATTRIBUTES, CRYPT_SIGN_MESSAGE_PARA, CRYPT_TIME_STAMP_REQUEST_INFO, CertFindAttribute


CRYPT_ATTRIBUTES

The CRYPT_ATTRIBUTES structure is used to specify an array of attributes.

typedef struct _CRYPT_ATTRIBUTES {
    DWORD              cAttr;
    PCRYPT_ATTRIBUTE   rgAttr;
} CRYPT_ATTRIBUTES,   *PCRYPT_ATTRIBUTES;

Members

cAttr
The number of elements in the array rgAttr.
rgAttr
An array of CRYPT_ATTRIBUTE structures.

See Also

CMSG_SIGNER_INFO, CRYPT_ATTRIBUTE, CryptMsgGetParam


CRYPT_ATTRIBUTE_TYPE_VALUE

The CRYPT_ATTRIBUTE_TYPE_VALUE structure is used to specify an attribute having only a single value. The Value's CRYPT_OBJID_BLOB is in its encoded representation.

typedef struct _CRYPT_ATTRIBUTE_TYPE_VALUE {
    LPSTR                       pszObjId;
    CRYPT_OBJID_BLOB            Value;
} CRYPT_ATTRIBUTE_TYPE_VALUE,  *PCRYPT_ATTRIBUTE_TYPE_VALUE;

Members

pszObjId
The object identifier that specifies the attribute type data contained in the Value blob.
Value
The encoded attribute.

See Also

BLOB Structure, CERT_ALT_NAME_ENTRY


CRYPT_BIT_BLOB

The CRYPT_BIT_BLOB structure is used for an array of bits. In a CRYPT_BIT_BLOB the last byte may contain zero to seven unused bits. Therefore, the overall bit length is cbData * 8 – cUnusedBits.

typedef struct _CRYPT_BIT_BLOB {
    DWORD             cbData;
    BYTE*             pbData;
    DWORD             cUnusedBits;
} CRYPT_BIT_BLOB,    *PCRYPT_BIT_BLOB;

Members

cbData
The count of bytes in the array pointed to by pbData.
pbData
A pointer to a block of data bytes.
cUnusedBits
The number of unused bits in the last byte of the array.

See Also

CERT_BASIC_CONSTRAINTS_INFO, CERT_INFO, CERT_KEY_ATTRIBUTES_INFO, CERT_KEY_USAGE_RESTRICTION_INFO, CERT_PUBLIC_KEY_INFO, CERT_SIGNED_CONTENT_INFO


CRYPT_CONTENT_INFO

The CRYPT_CONTENT_INFO structure is used to specify data encoded in the PKCS7 ContentInfo data format.

typedef struct _CRYPT_CONTENT_INFO {
    LPSTR               pszObjId;
    CRYPT_DER_BLOB      Content;
} CRYPT_CONTENT_INFO, *PCRYPT_CONTENT_INFO;

Members

pszObjId
The type of the data contained in the Content member. The ContentType in PKCS7 defines a set of predefined OIDs. However, additional OIDs may be defined and used.
Content
The data encoded in the PKCS7 ContentInfo data format.

See Also

PKCS_CONTENT_INFO


CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY

The CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY structure contains information representing the Netscape certificate sequence of certificates.

A Netscape certificate sequence of certificates may be created by setting the pszObjId = szOID_NETSCAPE_CERT_SEQUENCE and supplying DER encoded certificates in rgValue.

typedef struct _CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY {
    LPSTR               pszObjId;
    DWORD               cValue;
    PCRYPT_DER_BLOB     rgValue;
} CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY, *PCRYPT_CONTENT_INFO_SEQUENCE_OF_ANY;

Members

pszObjId
The object identifier that specifies the type of data contained in the rgValue array.
cValue
The number of elements in the array rgValue.
rgValue
An array of CRYPT_DER_BLOB structures. (See BLOB Structure.)

See Also

PKCS_CONTENT_INFO_SEQUENCE_OF_ANY, szOID_NETSCAPE_CERT_SEQUENCE


CRYPT_KEY_PROV_INFO

The CRYPT_KEY_PROV_INFO structure fields are passed as the arguments to CryptAcquireContext when attempting to acquire a handle to a particular key container within a particular cryptographic service provider (CSP), or to create or destroy key containers.

typedef struct _CRYPT_KEY_PROV_INFO {
    LPWSTR                 pwszContainerName;
    LPWSTR                 pwszProvName;
    DWORD                  dwProvType;
    DWORD                  dwFlags;
    DWORD                  cProvParam;
    PCRYPT_KEY_PROV_PARAM  rgProvParam;
    DWORD                  dwKeySpec;
} CRYPT_KEY_PROV_INFO,    *PCRYPT_KEY_PROV_INFO;

Members

pwszContainerName
A key container within a particular CSP.
pwszProvName
The name of the CSP.
dwProvType
The type of the CSP.

The following dwProvType values are defined in Wincrypt.h:

#define PROV_RSA_FULL              1
#define PROV_RSA_SIG               2
#define PROV_DSS                   3
#define PROV_FORTEZZA              4
#define PROV_MS_EXCHANGE           5
#define PROV_SSL                   6
#define PROV_RSA_SCHANNEL         12
#define PROV_DSS_DH               13
#define PROV_DH_SCHANNEL          18
dwFlags
Indicates whether a key container is to be created or destroyed, and whether an application is allowed access to a key container.

The following flags are defined and must not collide with any CryptAcquireContext dwFlags definitions.
Flag name | Value | Description
CERT_SET_KEY_PROV_HANDLE_PROP_ID | 0x00000001 | Enables the handle to the key provider to be kept open for subsequent calls to the cryptographic functions.
CERT_SET_KEY_CONTEXT_PROP_ID | 0x00000001 | Enables the handle to the key provider to be kept open for subsequent calls to the cryptographic functions.

See CryptAcquireContext for the list of flags passed through. The above flags are cleared before CryptAcquireContext is called. The cryptographic functions CryptDecryptMessage, CryptSignMessage, CryptDecryptAndVerifyMessageSignature, and CryptSignAndEncryptMessage, internally perform a CryptAcquireContext operation (using the CRYPT_KEY_PROV_INFO from a certificate). When the CERT_SET_KEY_CONTEXT_PROP_ID or CERT_SET_KEY_PROV_HANDLE_PROP_ID flag is set, these cryptographic functions then can call CertSetCertificateContextProperty (CERT_KEY_CONTEXT_PROP_ID) to enable the handle to the key provider to be kept open for subsequent calls to the cryptographic functions mentioned that use that same certificate, which eliminates the need to perform another CryptAcquireContext, improving efficiency. Also, since some providers may require that a password be entered for calls to CryptAcquireContext, it is desirable for applications to minimize the number of CryptAcquireContext calls made. Handles to key providers that were kept open are automatically released when the store is closed.

For example, consider an e-mail application where five encrypted messages have been received, all encrypted with the same certificate. If the handle to the key provider is kept open after the first message is processed, then calls to CryptAcquireContext are not required for the four remaining messages.

cProvParam
The number of elements in the array rgProvParam.
rgProvParam
An array of structures, each holding CRYPT_KEY_PROV_PARAM information.
dwKeySpec
The specification of the private key.

The following dwKeySpec values are defined in Wincrypt.h for the default provider:

#define AT_KEYEXCHANGE              1
#define AT_SIGNATURE                2

See Also

CRYPT_KEY_PROV_PARAM, CertGetCertificateContextProperty, CertSetCertificateContextProperty


CRYPT_KEY_PROV_PARAM

The CRYPT_KEY_PROV_PARAM structure fields are passed as the arguments to CryptSetProvParam. This structure is pointed to by the rgProvParam in the CRYPT_KEY_PROV_INFO data structure.

typedef struct _CRYPT_KEY_PROV_PARAM {
    DWORD           dwParam;
    BYTE*           pbData;
    DWORD           cbData;
    DWORD           dwFlags;
} CRYPT_KEY_PROV_PARAM, *PCRYPT_KEY_PROV_PARAM;

Members

dwParam
The parameter number to set. See CryptSetProvParam for a list of values.
pbData
The parameter data buffer.
cbData
The size, in bytes, of the parameter data buffer.
dwFlags
This member is reserved for future use and should be zero in the interim.

See Also

CRYPT_KEY_PROV_INFO


CRYPT_SEQUENCE_OF_ANY

The CRYPT_SEQUENCE_OF_ANY structure contains an arbitrary list of encoded blobs.

typedef struct _CRYPT_SEQUENCE_OF_ANY {
    DWORD               cValue;
    PCRYPT_DER_BLOB     rgValue;
} CRYPT_SEQUENCE_OF_ANY, *PCRYPT_SEQUENCE_OF_ANY;

Members

cValue
The number of elements in the array rgValue.
rgValue
An array of CRYPT_DER_BLOB structures. (See BLOB Structure.)

See Also

X509_SEQUENCE_OF_ANY


CRYPT_TIME_STAMP_REQUEST_INFO

The CRYPT_TIME_STAMP_REQUEST_INFO structure is used for time stamping. When signing an executable, you may wish to add an authenticated attribute that can be used to verify when the executable was signed. To do this, a signed time stamp must be requested from a time stamp server. The structure used to get a time stamp is the CRYPT_TIME_STAMP_REQUEST_INFO. It contains the signature bits of the material being time stamped in the Content field.

typedef struct _CRYPT_TIME_STAMP_REQUEST_INFO {
    LPSTR                   pszTimeStampAlgorithm;   // pszObjId
    LPSTR                   pszContentType;          // pszObjId
    CRYPT_OBJID_BLOB        Content;
    DWORD                   cAttribute;
    PCRYPT_ATTRIBUTE        rgAttribute;
} CRYPT_TIME_STAMP_REQUEST_INFO, *PCRYPT_TIME_STAMP_REQUEST_INFO;

Members

pszTimeStampAlgorithm
This OID specifies the desired format of the time stamp data, usually UTC.
pszContentType
The Content Type OID for the content, usually DATA.
Content
An encoded blob containing the signature bits of the material being time stamped.
cAttribute
The number of elements in the array rgAttribute.
rgAttribute
An array of structures, each holding CRYPT_ATTRIBUTE information about the certificate (encoded form).

See Also

BLOB Structure, CRYPT_ATTRIBUTE


CTL_ANY_SUBJECT_INFO

The CTL_ANY_SUBJECT_INFO structure is used to specify the SubjectAlgorithm to be matched in the CTL and the SubjectIdentifier to be matched in one of the CTL entries in calls to CertFindSubjectInCTL.

typedef struct _CTL_ANY_SUBJECT_INFO {
    CRYPT_ALGORITHM_IDENTIFIER  SubjectAlgorithm;
    CRYPT_DATA_BLOB             SubjectIdentifier;
} CTL_ANY_SUBJECT_INFO, *PCTL_ANY_SUBJECT_INFO;

Members

SubjectAlgorithm
A structure that contains the subjects algorithm type (SubjectAlgorithm.pszObjId) and any associated additional parameters (SubjectAlgorithm.Parameters). The pszObjId can be set to NULL to exclude the SubjectAlgorithm comparison.
SubjectIdentifier
Uniquely identifies the subject.

See Also

BLOB Structure, CRYPT_ALGORITHM_IDENTIFIER, CTL_FIND_SUBJECT_PARA, CertFindCTLInStore, CertFindSubjectInCTL


CTL_CONTEXT

The CTL_CONTEXT structure. A CTL context contains both the encoded and decoded representations of a CTL. It also contains an opened HCRYPTMSG handle to the decoded cryptographic signed message containing the CTL_INFO as its inner content.

The CryptMsg APIs can be used to extract additional signer information.

A CTL context returned by a certificate store function must be freed by calling the CertFreeCTLContext function. The CertDuplicateCTLContext function can be called to make a duplicate copy (which also must be freed by calling CertFreeCTLContext).

typedef struct _CTL_CONTEXT {
    DWORD           dwMsgAndCertEncodingType;
    BYTE*           pbCtlEncoded;
    DWORD           cbCtlEncoded;
    PCTL_INFO       pCtlInfo;
    HCERTSTORE      hCertStore;
    HCRYPTMSG       hCryptMsg;
    BYTE*           pbCtlContent;
    DWORD           cbCtlContent;
} CTL_CONTEXT,     *PCTL_CONTEXT;
typedef const CTL_CONTEXT *PCCTL_CONTEXT;

Members

dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pbCtlEncoded
A pointer to the encoded CTL.
cbCtlEncoded
The size, in bytes, of the encoded CTL.
pCrtInfo
A pointer to a structure of CTL information.
hCertStore
A handle to the certificate store.
hCryptMsg
An opened HCRYPTMSG handle to the decoded cryptographic signed message containing the CTL_INFO as its inner content.
pbCtlContent
The encoded inner content of the signed message.
cbCtlContent
The count, in bytes, of pbCtlContent.

See Also

CTL_INFO, CertAddCTLContextToStore, CertAddEncodedCTLToStore, CertCreateCTLContext, CertEnumCTLsInStore, CertFindCTLInStore, CertFindSubjectInCTL, CertFreeCTLContext, CryptMsgGetAndVerifySigner, CryptMsgSignCTL


CTL_ENTRY

The CTL_ENTRY structure is an entry in a CTL.

typedef struct _CTL_ENTRY {
    CRYPT_DATA_BLOB     SubjectIdentifier;   // For example, its hash
    DWORD               cAttribute;
    PCRYPT_ATTRIBUTE    rgAttribute;         // OPTIONAL
} CTL_ENTRY, *PCTL_ENTRY;

Members

SubjectIdentifier
Uniquely identifies the subject. It can be a hash or any unique byte sequence.
cAttribute
The count of elements in rgAttribute.
rgAttribute
An optional array of structures, each holding CRYPT_ATTRIBUTE information about the subject.

See Also

BLOB Structure, CTL_INFO, CRYPT_ATTRIBUTE


CTL_FIND_SUBJECT_PARA

The CTL_FIND_SUBJECT_PARA structure is used by CertFindCTLInStore with a dwFindType of CTL_FIND_SUBJECT.

typedef struct _CTL_FIND_SUBJECT_PARA {
    DWORD                   cbSize;
    PCTL_FIND_USAGE_PARA    pUsagePara; // optional
    DWORD                   dwSubjectType;
    void                    *pvSubject;
} CTL_FIND_SUBJECT_PARA, *PCTL_FIND_SUBJECT_PARA;

Members

cbSize
Count of bytes in this data structure.
pUsagePara
Pointer to a CTL_FIND_USAGE_PARA data structure. If there is no need to reference the CTL_FIND_USAGE_PARA parameters when finding a CTL, NULL may be specified.
dwSubjectType
For CTL_CERT_SUBJECT_TYPE, pvSubject points to a CERT_CONTEXT. The CTL's SubjectAlgorithm is examined to determine the representation of the subject's identity. Initially, only SHA1 or MD5 hash will be supported. The appropriate hash property is obtained from the CERT_CONTEXT.

For CTL_ANY_SUBJECT_TYPE, pvSubject points to the CTL_ANY_SUBJECT_INFO structure which contains the SubjectAlgorithm to be matched in the CTL and the SubjectIdentifer to be matched in one of the CTL entries.

pvSubject
pvSubject depends on the dwSubjectType. See dwSubjectType for details.

See Also

CERT_CONTEXT, CTL_ANY_SUBJECT_INFO, CTL_FIND_USAGE_PARA, CertFindCTLInStore


CTL_FIND_USAGE_PARA

The CTL_FIND_USAGE_PARA structure is a member of the CTL_FIND_SUBJECT_PARA structure and it is used by CertFindCTLInStore.

typedef struct _CTL_FIND_USAGE_PARA {
    DWORD               cbSize;
    CTL_USAGE           SubjectUsage;   // optional
    CRYPT_DATA_BLOB     ListIdentifier; // optional
    PCERT_INFO          pSigner;        // optional
} CTL_FIND_USAGE_PARA, *PCTL_FIND_USAGE_PARA;

Members

cbSize
The count of bytes in this data structure.
SubjectUsage
The SubjectUsage is represented as a sequence of object identifiers that need to be matched when finding a CTL.

A found CTL must contain all the usage object identifiers specified by SubjectUsage.

SubjectUsage.cUsageIdentifier can be set to zero to match any usage.

ListIdentifier
Specify the ListIdentifier if you want to restrict to a particular signer CTL list. It will then be used to match the ListIdentifier in a CTL. Normally the ListIdentifier will be zero, indicating that any ListIdentifier can be matched.

If you want to match only lists that have no ListIdentifier then ListIdentifier.cbData should be set to CTL_FIND_NO_LIST_ID_CBDATA to match CTLs with no specified ListIdentifier.

If the issuer creates multiple trust lists for the same SubjectUsage in a CTL_INFO structure, then, the ListIdentifier must be specified to distinguish between them.

pSigner
Specifies the signer to be matched when finding a CTL. Only the issuer and serial number from the CERT_INFO are used to match a signer.

To match any signer, NULL may be used. To match CTLs that don't have any signers, specify CTL_FIND_NO_SIGNER_PTR.

The CertEncodingType of the signer is obtained from the dwMsgAndCertEncodingType parameter of CertFindCTLInStore.

See Also

BLOB Structure, CERT_INFO, CTL_FIND_SUBJECT_PARA, CTL_USAGE, CertFindCTLInStore


CTL_INFO

The CTL_INFO structure contains the information stored in a Certificate Trust List (CTL).

typedef struct _CTL_INFO {
    DWORD                       dwVersion;
    CTL_USAGE                   SubjectUsage;
    CRYPT_DATA_BLOB             ListIdentifier;     // OPTIONAL
    CRYPT_INTEGER_BLOB          SequenceNumber;     // OPTIONAL
    FILETIME                    ThisUpdate;
    FILETIME                    NextUpdate;         // OPTIONAL
    CRYPT_ALGORITHM_IDENTIFIER  SubjectAlgorithm;
    DWORD                       cCTLEntry;
    PCTL_ENTRY                  rgCTLEntry;         // OPTIONAL
    DWORD                       cExtension;
    PCERT_EXTENSION             rgExtension;        // OPTIONAL
} CTL_INFO, *PCTL_INFO;

Members

dwVersion
The CTL's version number. Currently defined version numbers are shown in the following table.
CTL version name | Value
CTL_V1 | 0

SubjectUsage
The SubjectUsage identifies the intended usage of the list and is represented as a sequence of object identifiers. This is the same as in the Enhanced Key Usage extension.
ListIdentifier
An arbitrary byte string that uniquely identifies the list. This member is used to augment the SubjectUsage and further specifies the list when desired.
SequenceNumber
Used to convey a monotonically increasing number for each update of the CTL.
ThisUpdate
Indicates when a CTL was published. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
NextUpdate
Indicates when the next update of a CTL is scheduled to be available. It can be zero to indicate that there is no next update scheduled. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
SubjectAlgorithm
A structure that contains the algorithm type of the SubjectIdentifier in the array of CTL entries, and any associated additional parameters.
cCTLEntry
The number of elements in rgCTLEntry.
rgCTLEntry
An array of structures, each holding CTL_ENTRY information.
cExtension
The number of elements in rgExtension.
rgExtension
An array of structures, each holding CERT_EXTENSION information.

See Also

BLOB Structure, CERT_EXTENSION, CRYPT_ALGORITHM_IDENTIFIER, CTL_CONTEXT, CTL_ENTRY, CTL_USAGE


CTL_USAGE

The CTL_USAGE structure is used with the X509_ENHANCED_KEY_USAGE extension in CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject, and CryptDecodeObjectEx.

typedef struct _CTL_USAGE {
    DWORD               cUsageIdentifier;
    LPSTR               *rgpszUsageIdentifier;  // array of pszObjId
} CTL_USAGE, *PCTL_USAGE,
  CERT_ENHKEY_USAGE, *PCERT_ENHKEY_USAGE;

Members

cUsageIdentifier
The number of elements in rgpszUsageIdentifier.
rgpszUsageIdentifier
An array of object identifiers.

See Also

CTL_INFO, CTL_FIND_USAGE_PARA, CertFindCertificateInStore, CertGetCertificateContextProperty, CertVerifyCTLUsage, CryptDecodeObject, CryptEncodeObject


CTL_VERIFY_USAGE_PARA

The CTL_VERIFY_USAGE_PARA structure is used to specify parameters for CertVerifyCTLUsage.

typedef struct _CTL_VERIFY_USAGE_PARA {
    DWORD                   cbSize;
    CRYPT_DATA_BLOB         ListIdentifier;     // OPTIONAL
    DWORD                   cCtlStore;
    HCERTSTORE              *rghCtlStore;       // OPTIONAL
    DWORD                   cSignerStore;
    HCERTSTORE              *rghSignerStore;    // OPTIONAL
} CTL_VERIFY_USAGE_PARA, *PCTL_VERIFY_USAGE_PARA;

Members

cbSize
The count of bytes in this data structure.
ListIdentifier
Specify the ListIdentifier if you want to restrict to a particular signer CTL list. It will then be used to match the ListIdentifier in a CTL. Normally the ListIdentifier will be zero, indicating that any ListIdentifier can be matched.

If you want to match only lists that have no ListIdentifier then ListIdentifier.cbData should be set to CTL_FIND_NO_LIST_ID_CBDATA to match CTLs with no specified ListIdentifier.

If the issuer creates multiple trust lists for the same SubjectUsage in a CTL_INFO structure, then, the ListIdentifier must be specified to distinguish between them.

cCtlStore
The count of stores containing CTLs.
rghCtlStore
Specifies the stores to be searched to find the CTL by CertVerifyCTLUsage.
cSignerStore
The count of stores containing signers.
rghSignerStore
Specifies the stores containing acceptable CTL signers.

See Also

CertVerifyCTLUsage


CTL_VERIFY_USAGE_STATUS

The CTL_VERIFY_USAGE_STATUS structure is used by CertVerifyCTLUsage to return the CTL containing the subject, the subject's index into the CTL's array of entries, and the signer of the CTL.

typedef struct _CTL_VERIFY_USAGE_STATUS {
    DWORD                   cbSize;
    DWORD                   dwError;
    DWORD                   dwFlags;
    PCCTL_CONTEXT           *ppCtl;             // IN OUT OPTIONAL
    DWORD                   dwCtlEntryIndex;
    PCCERT_CONTEXT          *ppSigner;          // IN OUT OPTIONAL
    DWORD                   dwSignerIndex;
} CTL_VERIFY_USAGE_STATUS, *PCTL_VERIFY_USAGE_STATUS;

Members

cbSize
The count of bytes in this data structure.

Upon input to CertVerifyCTLUsage, cbSize must be set to a size >= sizeof(CTL_VERIFY_USAGE_STATUS). Otherwise, CertVerifyCTLUsage returns FALSE and sets LastError to E_INVALIDARG.

dwError
If FALSE is returned by CertVerifyCTLUsage, dwError specifies the error status. LastError as reported from CertVerifyCTLUsage is also set to this error status. See the table in the "Return Values" section in CertVerifyCTLUsage for the list of error values.
dwFlags
CERT_VERIFY_UPDATED_CTL_FLAG indicates that the time invalid CTL in the store was updated with a new CTL.
ppCtl
On input, ppCtl can be null indicating that the caller is not interested in obtaining the CTL containing the subject. On output, *ppCtl is a pointer to the returned CTL containing the subject.

Returned contexts must be freed via the store's free context APIs.

dwCtlEntryIndex
Returns the subject's index into the CTL's array of entries.
ppSigner
On input, ppSigner can be null indicating that the caller is not interested in obtaining the signer of the CTL. On output, *ppSigner is a pointer to the returned signer of the CTL.

Returned contexts must be freed via the store's free context APIs.

dwSignerIndex
A message might have more than one signer. dwSignerIndex is the index of the signer that was actually used.

See Also

CERT_CONTEXT, CTL_CONTEXT, CertVerifyCTLUsage


X.509 Certificate Extension Data Structures

The structures contained in this section are associated with X.509 CERT_EXTENSION structures. They are created when an encoded Value member of an CERT_EXTENSION structure is decoded using a call to CryptDecodeObject. The type of structure that is created depends on the string value residing in the CERT_EXTENSION structure's pszObjId member at the time of the call.

Currently defined extension object identifiers are shown in the following table.

Predefined Constant | Object identifier | Value | Data structure
X509_AUTHORITY_INFO_ACCESS | szOID_AUTHORITY_INFO_ACCESS | "1.3.6.1.5.5.7.1.1" | CERT_AUTHORITY_INFO_ACCESS
X509_AUTHORITY_KEY_ID | szOID_AUTHORITY_KEY_IDENTIFIER | "2.5.29.1" | CERT_AUTHORITY_KEY_ID_INFO
X509_KEY_ATTRIBUTES | szOID_KEY_ATTRIBUTES | "2.5.29.2" | CERT_KEY_ATTRIBUTES_INFO
X509_KEY_USAGE_RESTRICTION | szOID_KEY_USAGE_RESTRICTION | "2.5.29.4" | CERT_KEY_USAGE_RESTRICTION_INFO
None | szOID_POLICY_MAPPINGS | "2.5.29.5" | Not implemented
X509_ALTERNATE_NAME | szOID_SUBJECT_ALT_NAME | "2.5.29.7" | CERT_ALT_NAME_INFO
X509_ALTERNATE_NAME | szOID_ISSUER_ALT_NAME | "2.5.29.8" | CERT_ALT_NAME_INFO
None | szOID_SUBJECT_DIR_ATTRS | "2.5.29.9" | Not implemented
X509_BASIC_CONSTRAINTS | szOID_BASIC_CONSTRAINTS | "2.5.29.10" | CERT_BASIC_CONSTRAINTS_INFO
X509_KEY_USAGE | szOID_KEY_USAGE | "2.5.29.15" | CRYPT_BIT_BLOB
X509_BASIC_CONSTRAINTS2 | szOID_BASIC_CONSTRAINTS2 | "2.5.29.19" | CERT_BASIC_CONSTRAINTS2_INFO
X509_CERT_POLICIES | szOID_CERT_POLICIES | "2.5.29.32" | CERT_POLICIES_INFO


CERT_ACCESS_DESCRIPTION

The CERT_ACCESS_DESCRIPTION structure is used in CERT_AUTHORITY_INFO_ACCESS. It contains one instance of information on how to access CA information and services for the issuer of the certificate in which the CERT_AUTHORITY_INFO_ACCESS extension appears. Information and services may include on-line validation services and CA policy data.

CERT_ACCESS_DESCRIPTION is a component of CERT_AUTHORITY_INFO_ACCESS.

typedef struct _CERT_ACCESS_DESCRIPTION {
    LPSTR               pszAccessMethod;        // pszObjId
    CERT_ALT_NAME_ENTRY AccessLocation;
} CERT_ACCESS_DESCRIPTION, *PCERT_ACCESS_DESCRIPTION;

Members

pszAccessMethod
Specifies the object identifier for the method of access. Currently defined PKIX Access Method object identifiers are shown in the following table.
PKIX Access Method | Object Identifier
szOID_PKIX_OCSP | "1.3.6.1.5.5.7.48.1"
szOID_PKIX_CA_ISSUERS | "1.3.6.1.5.5.7.48.2"

When szOID_PKIX_OCSP is used for the access method, the AccessLocation member describes the on-line status server and the access protocol to obtain current certificate status information for the certificate containing this extension.

When szOID_PKIX_CA_ISSUERS is used for the access method, the AccessLocation member can be used to obtain a description of the CAs that have issued certificates superior to the CA that issued the certificate containing this extension. The CA issuer's description is intended to aid certificate user's in the selection of a certification path that terminates at a point trusted by the certificate user.

AccessLocation
Describes the on-line status server and the access protocol to obtain current certificate status information for the certificate containing the extension.

See Also

CERT_AUTHORITY_INFO_ACCESS


CERT_ALT_NAME_ENTRY

The CERT_ALT_NAME_ENTRY structure contains one or more alternative names, using any of a variety of name forms, which are bound by the CA to the certified public key.

CERT_ALT_NAME_ENTRY is a component of CERT_ALT_NAME_INFO.

typedef struct _CERT_ALT_NAME_ENTRY {
    DWORD    dwAltNameChoice;
    union {
      PCERT_OTHER_NAME              OtherName;
      LPWSTR                        pwszRfc822Name;
      LPWSTR                        pwszDNSName;
      \\Not implemented             x400Address;
      CERT_NAME_BLOB                DirectoryName;
      \\Not implemented             pwszEdiPartyName;
      LPWSTR                        pwszURL;
      CRYPT_DATA_BLOB               IPAddress;
      LPSTR                         pszRegisteredID;
    };
} CERT_ALT_NAME_ENTRY,   *PCERT_ALT_NAME_ENTRY;

Members

dwAltNameChoice
Indicates the variant used for the alternative name data contained in the union.

The following dwAltNameChoice values are defined in Wincrypt.h:

#define CERT_ALT_NAME_OTHER_NAME         1
#define CERT_ALT_NAME_RFC822_NAME        2
#define CERT_ALT_NAME_DNS_NAME           3
#define CERT_ALT_NAME_X400_ADDRESS       4
#define CERT_ALT_NAME_DIRECTORY_NAME     5
#define CERT_ALT_NAME_EDI_PARTY_NAME     6
#define CERT_ALT_NAME_URL                7
#define CERT_ALT_NAME_IP_ADDRESS         8
#define CERT_ALT_NAME_REGISTERED_ID      9
pOtherName
The name of a type as set in dwAltNameChoice.
pwszRfc822Name
An e-mail address.
pwszDNSName
An IA5 string.
x400Address
An OR address. Not currently implemented.
DirectoryName
A name.
pszEdiPartyName
An IA5 string. Not currently implemented.
pwszURL
An IA5 string (URL).
IPAddress
An octet string which is an Internet Protocol address defined in accordance with Internet RFC 791.
pszRegisteredID
An identifier of any registered object.

See Also

BLOB Structure, CERT_ALT_NAME_INFO, CRYPT_ATTRIBUTE_TYPE_VALUE


CERT_ALT_NAME_INFO

The CERT_ALT_NAME_INFO structure is used to encode/decode subject or issuer extensions.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.7" or "2.5.29.8", this CERT_ALT_NAME_INFO is output from the function call.

typedef struct _CERT_ALT_NAME_INFO {
    DWORD                  cAltEntry;
    PCERT_ALT_NAME_ENTRY   rgAltEntry;
 } CERT_ALT_NAME_INFO,    *PCERT_ALT_NAME_INFO

Members

cAltEntry
The number of elements in the array rgAltEntry.
rgAltEntry
An array of CERT_ALT_NAME_ENTRY structures.

See Also

CERT_ALT_NAME_ENTRY


CERT_AUTHORITY_INFO_ACCESS

The CERT_AUTHORITY_INFO_ACCESS structure can be used in a certificate extension to indicate how to access CA information and services for the issuer of the certificate in which the extension appears. Information and services may include on-line validation services and CA policy data. This extension may be included in subject or CA certificates, and it is always non-critical.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "1.3.6.1.5.5.7.1.1", this CERT_AUTHORITY_INFO_ACCESS is output from the function call.

typedef struct _CERT_AUTHORITY_INFO_ACCESS {
    DWORD                       cAccDescr;
    PCERT_ACCESS_DESCRIPTION    rgAccDescr;
} CERT_AUTHORITY_INFO_ACCESS, *PCERT_AUTHORITY_INFO_ACCESS;

Members

cAccDescr
The number of elements in the array rgAccDescr.
rgAccDescr
Each entry in rgAccDescr describes the format and location of additional information about the CA that issued the certificate in which the extension appears.

See Also

CERT_ACCESS_DESCRIPTION


CERT_AUTHORITY_KEY_ID_INFO

The CERT_AUTHORITY_KEY_ID_INFO structure, which can be used for either a certificate extension or a CRL extension, identifies the CA's key used to sign the certificate or CRL. It enables distinct keys used by the same CA to be differentiated (for example, as key updating occurs). The key may be identified by an explicit key identifier, by identification of a certificate for the key (giving certificate issuer and certificate serial number), or both. If both are used then the certificate issuer shall ensure that all three fields are consistent.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.1", this CERT_AUTHORITY_KEY_ID_INFO is output from the function call.

typedef struct _CERT_AUTHORITY_KEY_ID_INFO {
    CRYPT_DATA_BLOB              KeyId;
    CERT_NAME_BLOB               CertIssuer;
    CRYPT_INTEGER_BLOB           CertSerialNumber;
 } CERT_AUTHORITY_KEY_ID_INFO,  *PCERT_AUTHORITY_KEY_ID_INFO;

Members

KeyId
A unique identifier for a Certificate's public key.
CertIssuer
The distinguished name of the CA that issued the certificate (encoded form).
CertSerialNumber
The serial number of the certificate associated with the private key used to sign this certificate. See CERT_INFO for details.

See Also

BLOB Structure


CERT_AUTHORITY_KEY_ID2_INFO

The CERT_AUTHORITY_KEY_ID2_INFO structure differs from the CERT_AUTHORITY_KEY_ID_INFO structure in that the certificate issuer (AuthorityCertIssuer) is in a CERT_ALT_NAME_INFO representation instead of the distinguished name representation where a CERT_NAME_BLOB is used. Otherwise, the structures are used in the same way.

The CERT_AUTHORITY_KEY_ID2_INFO structure, which can be used for either a certificate extension or a CRL extension, identifies the CA's key used to sign the certificate or CRL. It enables distinct keys used by the same CA to be differentiated (for example, as key updating occurs). The key may be identified by an explicit key identifier, by identification of a certificate for the key (giving certificate issuer and certificate serial number), or both. If both are used then the certificate issuer shall ensure that all three fields are consistent.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.35", this CERT_AUTHORITY_KEY_ID2_INFO is output from the function call.

typedef struct _CERT_AUTHORITY_KEY_ID2_INFO {
    CRYPT_DATA_BLOB     KeyId;
    CERT_ALT_NAME_INFO  AuthorityCertIssuer;
    CRYPT_INTEGER_BLOB  AuthorityCertSerialNumber;
} CERT_AUTHORITY_KEY_ID2_INFO, *PCERT_AUTHORITY_KEY_ID2_INFO;

Members

KeyId
A unique identifier for a Certificate's public key.
AuthorityCertIssuer
Optional. Set its cAltEntry member to 0 to omit. The name of the CA that issued the certificate (encoded form).
AuthorityCertSerialNumber
The serial number of the certificate associated with the private key used to sign this certificate. See CERT_INFO for details.

See Also

CERT_ALT_NAME_INFO, CERT_AUTHORITY_KEY_ID_INFO


CERT_BASIC_CONSTRAINTS_INFO

The CERT_BASIC_CONSTRAINTS_INFO structure contains information indicating whether the certified subject may act as a CA, an end-entity, or both. If the subject may act as a CA, a certification path length constraint may also be specified, as may a set of subtrees within which all subject names in subsequent certificates in a certification path must be located. This extension can be used in validating certificates used to sign other certificates.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.10", this CERT_BASIC_CONSTRAINTS_INFO is output from the function call.

typedef struct _CERT_BASIC_CONSTRAINTS_INFO {
    CRYPT_BIT_BLOB               SubjectType;
    BOOL                         fPathLenConstraint;
    DWORD                        dwPathLenConstraint;
    DWORD                        cSubtreesConstraint;
    CERT_NAME_BLOB*              rgSubtreesConstraint;
 } CERT_BASIC_CONSTRAINTS_INFO, *PCERT_BASIC_CONSTRAINTS_INFO;

Members

SubjectType
Contains two bits of information. The first bit, CERT_CA_SUBJECT_FLAG, indicates that the subject may act as a CA, when it is set. The second bit, CERT_END_ENTITY_SUBJECT_FLAG, indicates that the subject may act as an end entity when it is set.
fPathLenConstraint
A flag indicating that the dwPathLenConstraint field is to be used to limit the allowed length of the certification path.
dwPathLenConstraint
Indicates the maximum number of CA certificates that may follow this certificate in a certification path. A value of zero indicates that the subject of this certificate may issue certificates only to end-entities and not to further CAs.
cSubtreesConstraint
The number of elements in the array rgSubtreesConstraint.
rgSubtreesConstraint
An array of CERT_NAME_BLOB structures associated with subtree constraints.

See Also

BLOB Structure, CRYPT_BIT_BLOB


CERT_BASIC_CONSTRAINTS2_INFO

The CERT_BASIC_CONSTRAINTS2_INFO structure contains information indicating whether the certified subject may act as a CA or an end-entity. If the subject may act as a CA, a certification path length constraint may also be specified.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.19", this CERT_BASIC_CONSTRAINTS2_INFO is output from the function call.

typedef struct _CERT_BASIC_CONSTRAINTS2_INFO {
    BOOL                           fCA;
    BOOL                           fPathLenConstraint;
    DWORD                          dwPathLenConstraint;
 } CERT_BASIC_CONSTRAINTS2_INFO,  *PCERT_BASIC_CONSTRAINTS2_INFO;

Members

fCA
TRUE indicates a CA. FALSE indicates an end-entity.
fPathLenConstraint
A flag indicating that the dwPathLenConstraint field is to be used to limit the allowed length of the certification path.
dwPathLenConstraint
Indicates the maximum number of CA certificates that may follow this certificate in a certification path. A value of zero indicates that the subject of this certificate may issue certificates only to end-entities and not to further CAs.


CERT_KEY_ATTRIBUTES_INFO

The CERT_KEY_ATTRIBUTES_INFO structure contains optional additional information about the public key being certified. It can include a key identifier, an indication of the intended use of that key, and/or an indication of the period of use of the corresponding private key.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.2", this CERT_KEY_ATTRIBUTES_INFO is output from the function call.

typedef struct _CERT_KEY_ATTRIBUTES_INFO {
    CRYPT_DATA_BLOB             KeyId;
    CRYPT_BIT_BLOB              IntendedKeyUsage;
    PCERT_PRIVATE_KEY_VALIDITY  pPrivateKeyUsagePeriod;  // optional
} CERT_KEY_ATTRIBUTES_INFO,    *PCERT_KEY_ATTRIBUTES_INFO;

Members

KeyId
The unique identifier of the key.
IntendedKeyUsage
This field indicates the intended purpose of the key, and is for use in finding the correct key or certificate of a user who has multiple keys or certificates. It is an advisory field and does not imply that usage of the key is restricted to the purpose indicated. The list of intended uses is not necessarily all-inclusive, and the field may be omitted. If the use of a key is to be restricted to a particular purpose, the key usage restriction extension shall be used. See the RestrictedKeyUsage field in CERT_KEY_USAGE_RESTRICTION_INFO for a list of bit values.
pPrivateKeyUsagePeriod
An optional data field. A pointer to a CERT_PRIVATE_KEY_VALIDITY structure that indicates the period of use of the private key corresponding to the certified public key.

See Also

BLOB Structure, CERT_PRIVATE_KEY_VALIDITY, CRYPT_BIT_BLOB


CERT_KEY_USAGE_RESTRICTION_INFO

The CERT_KEY_USAGE_RESTRICTION_INFO structure indicates a restriction imposed as to the purposes for which, and policies under which, the certified public key may be used.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.4", this CERT_KEY_USAGE_RESTRICTION_INFO is output from the function call.

typedef struct _CERT_KEY_USAGE_RESTRICTION_INFO {
    DWORD                            cCertPolicyId;
    PCERT_POLICY_ID                  rgCertPolicyId;
    CRYPT_BIT_BLOB                   RestrictedKeyUsage;
} CERT_KEY_USAGE_RESTRICTION_INFO,  *PCERT_KEY_USAGE_RESTRICTION_INFO;

Members

cCertPolicyId
The number of elements in the array rgCertPolicyId.
rgCertPolicyId
An array of structures, each holding CERT_POLICY_ID information.
RestrictedKeyUsage
This member, when present (indicated by RestrictedKeyUsage.cbData != 0), indicates that the certified key may be used only for a purpose for which a corresponding key usage bit is set.

Currently defined RestrictedKeyUsage values are shown in the following table.
RestrictedKeyUsage | Value
CERT_DATA_ENCIPHERMENT_KEY_USAGE | 0x10
CERT_DIGITAL_SIGNATURE_KEY_USAGE | 0x80
CERT_KEY_AGREEMENT_KEY_USAGE | 0x08
CERT_KEY_CERT_SIGN_KEY_USAGE | 0x04
CERT_KEY_ENCIPHERMENT_KEY_USAGE | 0x20
CERT_NON_REPUDIATION_KEY_USAGE | 0x40
CERT_OFFLINE_CRL_SIGN_KEY_USAGE | 0x02

See Also

CERT_POLICY_ID, CRYPT_BIT_BLOB


CERT_POLICY_ID

The CERT_POLICY_ID structure contains a list of certificate policies that the certificate is expressly recognized as supporting, together with optional qualifier information pertaining to these policies.

CERT_POLICY_ID is a component of CERT_KEY_USAGE_RESTRICTION_INFO.

typedef struct _CERT_POLICY_ID {
    DWORD          cCertPolicyElementId;
    LPSTR*         rgpszCertPolicyElementId;
} CERT_POLICY_ID, *PCERT_POLICY_ID;

Members

cCertPolicyElementId
The number of elements in the array rgpszCertPolicyElementId.
rgpszCertPolicyElementId
An array of pointers to policy element ID strings.

See Also

CERT_KEY_USAGE_RESTRICTION_INFO


CERT_POLICIES_INFO

The CERT_POLICIES_INFO structure contains an array of CERT_POLICY_INFO.

When the CryptDecodeObject or CryptDecodeObjectEx function is performed on a CERT_EXTENSION structure's Value member, and the structure's pszObjId member is set to "2.5.29.32", this CERT_POLICIES_INFO is output from the function call.

typedef struct _CERT_POLICIES_INFO {
    DWORD                cPolicyInfo;
    CERT_POLICY_INFO*    rgPolicyInfo;
} CERT_POLICIES_INFO,  *PCERT_POLICIES_INFO;

Members

cPolicyInfo
The number of elements in the array rgPolicyInfo.
rgPolicyInfo
An array of structures, each holding CERT_POLICY_INFO information.

See Also

CERT_POLICY_INFO


CERT_POLICY_INFO

The CERT_POLICY_INFO structure contains an object identifier string specifying the policy, and an optional array of policy qualifiers.

CERT_POLICY_INFO is a component of CERT_POLICIES_INFO.

typedef struct _CERT_POLICY_INFO {
    LPSTR                        pszPolicyIdentifier;
    DWORD                        cPolicyQualifier;
    CERT_POLICY_QUALIFIER_INFO*  rgPolicyQualifier;
} CERT_POLICY_INFO,            *PCERT_POLICY_INFO;

Members

pszPolicyIdentifier
An object identifier string specifying the policy.
cPolicyQualifier
The number of elements in the array rgPolicyQualifier.
rgPolicyQualifier
An array of structures, each holding CERT_POLICY_QUALIFIER_INFO information.

See Also

CERT_POLICIES_INFO, CERT_POLICY_QUALIFIER_INFO


CERT_POLICY_QUALIFIER_INFO

The CERT_POLICY_QUALIFIER_INFO structure contains an object identifier specifying the qualifier, and qualifier specific supplemental information.

CERT_POLICY_QUALIFIER_INFO is a component of CERT_POLICY_INFO.

typedef struct _CERT_POLICY_QUALIFIER_INFO {
    LPSTR                       pszPolicyQualifierId;
    CRYPT_OBJID_BLOB            Qualifier;
} CERT_POLICY_QUALIFIER_INFO,  *PCERT_POLICY_QUALIFIER_INFO;

Members

pszPolicyQualifierId
An object identifier specifying the qualifier.
Qualifier
The optional qualifier specific supplemental information.

See Also

BLOB Structure, CERT_POLICY_INFO


CERT_PRIVATE_KEY_VALIDITY

The CERT_PRIVATE_KEY_VALIDITY structure indicates the period of use of the private key corresponding to the certified public key. If the NotBefore component is not present, no statement is made as to when the validity period of the private key commences. If the NotAfter component is not present, no statement is made as to when the validity period of the private key concludes.

CERT_PRIVATE_KEY_VALIDITY is a component of CERT_KEY_ATTRIBUTES_INFO.

typedef struct _CERT_PRIVATE_KEY_VALIDITY{
    FILETIME                   NotBefore;
    FILETIME                   NotAfter;
} CERT_PRIVATE_KEY_VALIDITY,  *PCERT_PRIVATE_KEY_VALIDITY;

Members

NotBefore
A date, before which the private key is not valid. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.
NotAfter
A date, after which the private key is not valid. For X509_ASN_ENCODING, if the time is after 1950 and before 2050, it is UTC time encoded as a two-digit year precise to seconds. Otherwise, it is Generalized time encoded as a four-digit year precise to seconds.

See Also

CERT_KEY_ATTRIBUTES_INFO


CRL_DIST_POINT

The CRL_DIST_POINT structure identifies a CRL distribution point to which a certificate user should refer to ascertain if the certificate has been revoked. A certificate user can obtain a CRL from an applicable distribution point or it can obtain a current complete CRL from the CA directory entry.

typedef struct _CRL_DIST_POINT {
    CRL_DIST_POINT_NAME     DistPointName;      // OPTIONAL
    CRYPT_BIT_BLOB          ReasonFlags;        // OPTIONAL
    CERT_ALT_NAME_INFO      CRLIssuer;          // OPTIONAL
} CRL_DIST_POINT, *PCRL_DIST_POINT;

Members

DistPointName
Identifies the location from which the CRL can be obtained. If this component is absent, the distribution point name defaults to the CRL issuer name.
ReasonFlags
Indicates the revocation reasons covered by this CRL.

If the reasons component is absent, the corresponding CRL distribution point distributes a CRL which will contain an entry for this certificate if this certificate has been revoked, regardless of the revocation reason. Otherwise, the value indicates which revocation reasons are covered by the corresponding CRL distribution point.

Currently defined ReasonFlags values are shown in the following table.
ReasonFlags | Value
CRL_REASON_UNUSED_FLAG | 0x80
CRL_REASON_KEY_COMPROMISE_FLAG | 0x40
CRL_REASON_CA_COMPROMISE_FLAG | 0x20
CRL_REASON_AFFILIATION_CHANGED_FLAG | 0x10
CRL_REASON_SUPERSEDED_FLAG | 0x08
CRL_REASON_CESSATION_OF_OPERATION_FLAG | 0x04
CRL_REASON_CERTIFICATE_HOLD_FLAG | 0x02

CRLIssuer
Identifies the authority that issues and signs the CRL. If absent, the CRL issuer name defaults to the certificate issuer name.

See Also

CRL_DIST_POINTS_INFO, CRL_DIST_POINT_NAME


CRL_DIST_POINT_NAME

The CRL_DIST_POINT_NAME structure identifies the location from which the CRL can be obtained.

When the FullName alternative is used, or when the default applies, the CRL distribution point name may have multiple name forms. The same name, in at least one of its name forms shall be present in the DistPointName field (see CRL_DIST_POINT) of the issuing distribution point extension on the CRL. A certificate using system is not required to be able to process all name forms. It may use a distribution point provided at least one name form can be processed. If no name forms for a distribution point can be processed, a certificate using system can still use the certificate, provided requisite revocation information can be obtained from another source, for example, another distribution point of the CA's directory entry.

typedef struct _CRL_DIST_POINT_NAME {
    DWORD   dwDistPointNameChoice;
    union {
        CERT_ALT_NAME_INFO      FullName;       // 1
        // Not implemented      IssuerRDN;      // 2
    };
} CRL_DIST_POINT_NAME, *PCRL_DIST_POINT_NAME;

Members

dwDistPointNameChoice
Indicates the variant used for the name data contained in the union. The following dwDistPointNameChoice values are defined in Wincrypt.h:
#define CRL_DIST_POINT_NO_NAME          0
#define CRL_DIST_POINT_FULL_NAME        1
#define CRL_DIST_POINT_ISSUER_RDN_NAME  2
FullName
This structure contains one or more alternative names specifying the CRL distribution point name, using any of a variety of name forms. One of the most common name forms uses a URL in the form of http://… to specify the location of the CRL.
IssuerRDN
Not implemented.

See Also

CRL_DIST_POINT


CRL_DIST_POINTS_INFO

The CRL_DIST_POINTS_INFO structure identifies a list of CRL distribution point to which a certificate user should refer to ascertain if the certificate has been revoked.

typedef struct _CRL_DIST_POINTS_INFO {
    DWORD                   cDistPoint;
    PCRL_DIST_POINT         rgDistPoint;
} CRL_DIST_POINTS_INFO, *PCRL_DIST_POINTS_INFO;

Members

cDistPoint
The number of elements in the array rgDistPoint.
rgDistPoint
An array of CRL_DIST_POINT structures.

See Also

CRL_DIST_POINT


Low Level Message Data Structures

The data structures in this section are used by many of the low-level message functions.

These structures can be found in Wincrypt.h.


CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA

The CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA structure is used when adding an unauthenticated attribute to a signer of a signed message. This structure is passed to CryptMsgControl for a value of CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR in dwCtrlType.

typedef struct _CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA {
    DWORD               cbSize;
    DWORD               dwSignerIndex;
    CRYPT_DATA_BLOB     blob;
} CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA, *PCMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA;

Members

cbSize
The count of bytes in this data structure.
dwSignerIndex
The index of the signer in an array of a signed data message for which the unauthenticated attribute is to be added.
blob
The unauthenticated attribute to add is input in the form of an encoded blob.

See Also

BLOB Structure, CryptMsgControl


CMSG_CTRL_DECRYPT_PARA

The CMSG_CTRL_DECRYPT_PARA structure is used for an enveloped message. This structure is passed to CryptMsgControl for a value of CMSG_CTRL_DECRYPT in dwCtrlType.

Important changes have been made to the CryptoAPI in order to support S/MIME e-mail interoperability, which affect the handling of enveloped messages. See the Remarks for CryptMsgOpenToEncode for details.

typedef struct _CMSG_CTRL_DECRYPT_PARA {
    DWORD                    cbSize;
    HCRYPTPROV               hCryptProv;
    DWORD                    dwKeySpec;
    DWORD                    dwRecipientIndex;
} CMSG_CTRL_DECRYPT_PARA,   *PCMSG_CTRL_DECRYPT_PARA;

Members

cbSize
The count of bytes in this data structure.
hCryptProv
A handle to the cryptographic service provider.
dwKeySpec
Used to specify the private key to be used.

The following dwKeySpec values are defined in Wincrypt.h for the default provider:

#define AT_KEYEXCHANGE              1
#define AT_SIGNATURE                2

If dwKeySpec is zero, then the default AT_KEYEXCHANGE is used.

dwRecipientIndex
The index of the recipient in the message associated with the hCryptProv's private key.

See Also

CryptMsgControl


CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA

The CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA structure is used when deleting an unauthenticated attribute from a signer of a signed message. This structure is passed to CryptMsgControl for a value of CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR in dwCtrlType.

typedef struct _CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA {
    DWORD               cbSize;
    DWORD               dwSignerIndex;
    DWORD               dwUnauthAttrIndex;
} CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA, *PCMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA;

Members

cbSize
The count of bytes in this data structure.
dwSignerIndex
The index of the signer of a signed data message for which the unauthenticated attribute is to be deleted.
dwUnauthAttrIndex
The index of the unauthenticated attribute to be removed.

See Also

CryptMsgControl


CMSG_ENVELOPED_ENCODE_INFO

The CMSG_ENVELOPED_ENCODE_INFO structure is used for enveloped messages. This structure is passed to CryptMsgOpenToEncode for a value of CMSG_ENVELOPED in dwMsgType.

typedef struct _CMSG_ENVELOPED_ENCODE_INFO {
    DWORD                        cbSize;
    HCRYPTPROV                   hCryptProv;
    CRYPT_ALGORITHM_IDENTIFIER   ContentEncryptionAlgorithm;
    void*                        pvEncryptionAuxInfo;
    DWORD                        cRecipients;
    PCERT_INFO*                  rgpRecipients;
} CMSG_ENVELOPED_ENCODE_INFO,  *PCMSG_ENVELOPED_ENCODE_INFO;

Members

cbSize
The count of bytes in this data structure.
hCryptProv
Specifies a handle to the cryptographic service provider used to do the content encryption, recipient key encryption, and export. The hCryptProv's private keys aren't used.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

ContentEncryptionAlgorithm
Specifies the algorithm that is used to encrypt the contents.

The following encryption algorithms require that the ContentEncryptionAlgorithm's Parameters contain an encoded 8 byte Initialization Vector (IV) (see CryptSetKeyParam for more information about the KP_IV parameter).

szOID_OIWSEC_desCBC (CALG_DES)
szOID_RSA_DES_EDE3_CBC (CALG_3DES)
szOID_RSA_RC4 (CALG_RC4)

If the ContentEncryptionAlgorithm.Parameters.cbData = 0, then, an ASN.1 encoded OCTET STRING containing the IV is automatically generated. The IV is created using CryptGenRandom.

Note that when a message is decrypted, if it has an Initialization Vector parameter, the cryptographic message functions will call CryptSetKeyParam with the Initialization Vector before doing the decrypt.

The szOID_RSA_RC2CBC(CALG_RC2) algorithm requires the Parameters to be encoded as a CRYPT_RC2_CBC_PARAMETERS data structure. If the ContentEncryptionAlgorithm.Parameters.cbData = 0, then, an ASN.1 encoded CRYPT_RC2_CBC_PARAMETERS containing the IV is automatically generated, where the dwVersion corresponding to the 40 bit length is used for the default. To override the default 40 bit length, the pvEncryptionAuxInfo member can be used to point to a CMSG_RC2_AUX_INFO data structure which contains the bit length.

pvEncryptionAuxInfo
This parameter points to a CMSG_RC2_AUX_INFO data structure for RC2 encryption or a SMSG_SP3_COMPATIBLE_AUX_INFO data structure for SP3 compatible encryption. For anything other than RC2 or SP3 compatible encryption, pvEncryptionAuxInfo must be set to NULL.
cRecipients
The number of elements in the array rgpRecipients.
rgpRecipients
An array of structures, each holding recipient information. Provides the Issuer, SerialNumber, and SubjectPublicKeyInfo.

See Also

CERT_INFO, CRYPT_ALGORITHM_IDENTIFIER


CMSG_HASHED_ENCODE_INFO

The CMSG_HASHED_ENCODE_INFO structure is used with hashed messages. This structure is passed to CryptMsgOpenToEncode for a value of CMSG_HASHED in dwMsgType.

typedef struct _CMSG_HASHED_ENCODE_INFO {
    DWORD                      cbSize;
    HCRYPTPROV                 hCryptProv;
    CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
    void*                      pvHashAuxInfo;
} CMSG_HASHED_ENCODE_INFO,    *PCMSG_HASHED_ENCODE_INFO;

Members

cbSize
The count of bytes in this data structure.
hCryptProv
Specifies a handle to the cryptographic service provider used to do the hash. The hCryptProv's private keys aren't used.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

HashAlgorithm
A hash algorithm.
pvHashAuxInfo
Currently not used and must be set to NULL in the interim.

See Also

CRYPT_ALGORITHM_IDENTIFIER


CMSG_RC2_AUX_INFO

The CMSG_RC2_AUX_INFO structure contains auxiliary information for RC2 encryption algorithms. The pvEncryptionAuxInfo member in CMSG_ENVELOPED_ENCODE_INFO should be updated to point to this structure.

Note, this auxiliary information is only used when the ContentEncryptionAlgorithm's Parameters.cbData is zero. Otherwise, the Parameters member is decoded to get the bit length.

typedef struct _CMSG_RC2_AUX_INFO {
    DWORD                       cbSize;
    DWORD                       dwBitLen;
} CMSG_RC2_AUX_INFO, *PCMSG_RC2_AUX_INFO;

Members

cbSize
The count of bytes in this data structure.
dwBitLen
Specifies the RC2 effective key length. Currently 40 bit, 64 bit, and 128 bit lengths are supported. The value supplied is simply an DWORD with the integer value of 40, 64, or 128. (The values used here are not to be confused with the values used to specify the dwVersion in the CRYPT_RC2_CBC_PARAMETERS structure. The values used there for the defined constants that specify the length used are not the same as the length used.)

If the CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG is set, SP3 compatible encryption is done and the default bit length is ignored.

See Also

CMSG_ENVELOPED_ENCODE_INFO, CRYPT_ALGORITHM_IDENTIFIER


CMSG_SIGNED_ENCODE_INFO

The CMSG_SIGNED_ENCODE_INFO structure is used for signed messages. This structure is passed to CryptMsgOpenToEncode for a value of CMSG_SIGNED in dwMsgType.

typedef struct _CMSG_SIGNED_ENCODE_INFO {
    DWORD                      cbSize;
    DWORD                      cSigners;
    PCMSG_SIGNER_ENCODE_INFO   rgSigners;
    DWORD                      cCertEncoded;
    PCERT_BLOB                 rgCertEncoded;
    DWORD                      cCrlEncoded;
    PCRL_BLOB                  rgCrlEncoded;
} CMSG_SIGNED_ENCODE_INFO,   *PCMSG_SIGNED_ENCODE_INFO;

Members

cbSize
The count of bytes in this data structure.
cSigners
The number of elements in the array rgSigners.
rgSigners
An array of structures, each holding signer information.
cCertEncoded
The number of elements in the array rgCertEncoded.
rgCertEncoded
An array of structures, each holding an encoded certificate.
cCrlEncoded
The number of elements in the array rgCrlEncoded.
rgCrlEncoded
An array of structures, each holding an encoded CRL.

See Also

BLOB Structure, CMSG_SIGNER_ENCODE_INFO


CMSG_SIGNER_ENCODE_INFO

The CMSG_SIGNER_ENCODE_INFO structure is used to specify the signer information. This structure is passed to CryptMsgCountersign, CryptMsgCountersignEncoded, and optionally to CryptMsgOpenToEncode as a member of CMSG_SIGNED_ENCODE_INFO for a value of CMSG_SIGNED in dwMsgType.

typedef struct _CMSG_SIGNER_ENCODE_INFO {
    DWORD                       cbSize;
    PCERT_INFO                  pCertInfo;
    HCRYPTPROV                  hCryptProv;
    DWORD                       dwKeySpec;
    CRYPT_ALGORITHM_IDENTIFIER  HashAlgorithm;
    void*                       pvHashAuxInfo;
    DWORD                       cAuthAttr;
    PCRYPT_ATTRIBUTE            rgAuthAttr;
    DWORD                       cUnauthAttr;
    PCRYPT_ATTRIBUTE            rgUnauthAttr;
} CMSG_SIGNER_ENCODE_INFO,   *PCMSG_SIGNER_ENCODE_INFO;

Members

cbSize
The count of bytes in this data structure.
pCertInfo
The following data structures from the specified CERT_INFO are used:

Issuer

SerialNumber

SubjectPublicKeyInfo.Algorithm

The contents of the Issuer and SerialNumber data structures, combined are a unique identifier of a certificate. The Algorithm member of the SubjectPublicKeyInfo data structure specifies the hash encryption algorithm used.

hCryptProv
A handle to the cryptographic service provider.
dwKeySpec
Used to specify the private key to be used.

The following dwKeySpec values are defined in Wincrypt.h for the default provider:

#define AT_KEYEXCHANGE              1
#define AT_SIGNATURE                2

If dwKeySpec is zero, then the default AT_SIGNATURE is used.

HashAlgorithm
A hash algorithm.
pvHashAuxInfo
Currently not used and must be set to NULL in the interim.
cAuthAttr
The number of elements in the array rgAuthAttr.
rgAuthAttr
An array of structures, each holding authenticated attribute information. If no authenticated attributes are present in rgAuthAttr, then cAuthAttr should be zero. If there are authenticated attributes present, then the PKCS #9 standard dictates that there must be at least two attributes present, the content type object identifier, and the hash of the message itself. These attributes are automatically added by the system.
cUnauthAttr
The number of elements in the array rgUnauthAttr.
rgUnauthAttr
An array of structures, each holding unauthenticated attribute information. If no unauthenticated attributes are present in rgUnauthAttr, then cUnauthAttr should be zero. Unauthenticated attributes may be used to contain countersignatures, among other uses.

See Also

CERT_INFO, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_ATTRIBUTE, CryptMsgControl, CryptMsgCountersign


CMSG_SIGNER_INFO

The CMSG_SIGNER_INFO structure is used to hold the content of the SignerInfo, as defined by PKCS # 7, in a signed or a signed and enveloped message. When decoding a received message, for each of the signers, CryptMsgGetParam is called to get the SignerInfo.

typedef struct _CMSG_SIGNER_INFO {
    DWORD                       dwVersion;
    CERT_NAME_BLOB              Issuer;
    CRYPT_INTEGER_BLOB          SerialNumber;
    CRYPT_ALGORITHM_IDENTIFIER  HashAlgorithm;
    CRYPT_ALGORITHM_IDENTIFIER  HashEncryptionAlgorithm;
    CRYPT_DATA_BLOB             EncryptedHash;
    CRYPT_ATTRIBUTES            AuthAttrs;
    CRYPT_ATTRIBUTES            UnauthAttrs;
} CMSG_SIGNER_INFO,           *PCMSG_SIGNER_INFO;

Members

dwVersion
The version of this structure.
Issuer
Identifies the issuer of the certificate that contains the public key, which should be used to verify this signature.
SerialNumber
Identifies the serial number of the certificate that contains the public key, which should be used to verify this signature. See CERT_INFO for details.
HashAlgorithm
The algorithm for use in generating the hash of a message.
HashEncryptionAlgorithm
The algorithm that was used to encrypt the hash.
EncryptedHash
The encrypted hash (the signature).
AuthAttrs
The authenticated attributes for the signer.
UnauthAttrs
The unauthenticated attributes for the signer.

See Also

BLOB Structure, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_ATTRIBUTES


CMSG_STREAM_INFO

The CMSG_STREAM_INFO structure is used when you want to stream data rather than process it as a single block (for example, when processing very large messages). Messages may originate from any serialized source of data, such as a file on a hard disk, a server, CD ROM, etc.

This structure is passed to CryptMsgOpenToEncode and CryptMsgOpenToDecode.

Messages can be so large that processing them all at once by storing the data in memory can be difficult, if not impossible, depending on the amount of memory available on your computer. It is possible to process large messages without encountering memory limitations by streaming the data that is to be processed, in manageable sized blocks. The low-level message functions can be used when streaming to encode a message, and when streaming to decode a message. Any level of nesting of messages is supported when streaming to encode and streaming to decode.

The input message that is to be processed as a stream, is fed into CryptMsgUpdate by the application one block at a time, with the application determining the size of the block. As the streamed message is processed for encoding or decoding, the resulting output data is passed back to the application through an application specified callback function specified by the pfnStreamOutput member.

No assumptions should be made about the block size of the output data, since the size can vary for several reasons. When processing an enveloped message, the block size for the encryption algorithm can cause jitter in the output data block size. When processing input data, blocks that contain the message header and the SignerInfo (as defined by PKCS # 7) can affect output data block size.

The size of the output block is passed to the callback function in cbData. The application decides how to use the output data. Typically, this output data will not be persisted in memory as a whole by the application due to memory limitations, but will be serialized to a file on a hard disk, or a server, etc.

typedef struct _CMSG_STREAM_INFO {
    DWORD                    cbContent;
    PFN_CMSG_STREAM_OUTPUT   pfnStreamOutput;
    void                    *pvArg;
} CMSG_STREAM_INFO, *PCMSG_STREAM_INFO;

Members

cbContent
Specifies the count of bytes of the content. DER encoding is used unless a 0xFFFFFFFF is passed, which indicates that the application is not specifying the length and forces indefinite-length BER encoding to be used.
pfnStreamOutput
The address of a callback function. Typically, this callback is used to read and write data to a disk when processing large messages.
pvArg
The argument to pass to the callback function. Typically, this is used for state data which includes the handle to a more deeply nested message (when decoding) or a less deeply nested message (when encoding).

pfnStreamOutputCallback

An application-defined callback function that is called by CryptMsgUpdate (for encode and decode of messages) and by CryptMsgControl (when decoding enveloped messages) when streaming is being used. Streaming is enabled when pStreamInfo is not NULL in calls to CryptMsgOpenToDecode and CryptMsgOpenToEncode.

BOOL WINAPI CmsgStreamOutputCallback(
  IN const void *pvArg,  //in
  IN BYTE *pbData,       //in
  IN DWORD cbData,       //in
  IN BOOL fFinal         //in
);

Parameters

pvArg
The arguments specified by CMSG_STREAM_INFO.
pbData
A pointer to a block of processed data that is available to the application.
cbData
The size, in bytes, of the block of processed data at pbData.
fFinal
Specifies that the last block of data is being processed and that this is the last time the callback will be executed.


Simplified Message Data Structures

The data structures in this section are used by the Simplified Message Functions, and can be found in Wincrypt.h.


CRYPT_DECRYPT_MESSAGE_PARA

The CRYPT_DECRYPT_MESSAGE_PARA structures are used for decrypting messages.

typedef struct _ CRYPT_DECRYPT_MESSAGE_PARA {
    DWORD                       cbSize;
    DWORD                       dwMsgAndCertEncodingType;
    DWORD                       cCertStore;
    HCERTSTORE*                 rghCertStore;
} CRYPT_DECRYPT_MESSAGE_PARA,  *PCRYPT_DECRYPT_MESSAGE_PARA;

Members

cbSize
Must be set to the size of this data structure.
dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

cCertStore
The number of elements in the array rghCertStore.
rghCertStore
An array of certificate store handles.

These certificate store handles are used to obtain the certificate context to use for decrypting a message. See the decryption functions CryptDecryptMessage, and CryptDecryptAndVerifyMessageSignature. An encrypted message can have one or more recipients. The recipients are identified by their certificate ID (certificate issuer and serial number). The certificate stores are searched to find the certificate context corresponding to the certificate ID.

Only certificate contexts in the store with one of the following properties, CERT_KEY_PROV_INFO_PROP_ID, or CERT_KEY_CONTEXT_PROP_ID can be used. These properties specify the private exchange key to use.

See Also

CryptDecryptAndVerifyMessageSignature, CryptDecryptMessage


CRYPT_ENCRYPT_MESSAGE_PARA

The CRYPT_ENCRYPT_MESSAGE_PARA structure is used for encrypting messages.

typedef struct _CRYPT_ENCRYPT_MESSAGE_PARA {
    DWORD                       cbSize;
    DWORD                       dwMsgEncodingType;
    HCRYPTPROV                  hCryptProv;
    CRYPT_ALGORITHM_IDENTIFIER  ContentEncryptionAlgorithm;
    void                        *pvEncryptionAuxInfo;
    DWORD                       dwFlags;
    DWORD                       dwInnerContentType;
} CRYPT_ENCRYPT_MESSAGE_PARA, *PCRYPT_ENCRYPT_MESSAGE_PARA;

Members

cbSize
Must be set to the size of this data structure.
dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

hCryptProv
Specifies a handle to the cryptographic service provider to be used for encryption. The CSP identified by hCryptProv is used to do content encryption, recipient key encryption, and recipient key export. Its private key isn't used.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

ContentEncryptionAlgorithm
The object identifier of the encryption algorithm, for example, szOID_RSA_RC4, szOID_RSA_RC2CBC, or szOID_OIWSEC_desCBC. The hCryptProv CSP must support the encryption algorithm.

The following encryption algorithms require that the ContentEncryptionAlgorithm's Parameters contain an encoded 8 byte Initialization Vector (IV) (see CryptSetKeyParam for more information about the KP_IV parameter).

szOID_OIWSEC_desCBC (CALG_DES)
szOID_RSA_DES_EDE3_CBC (CALG_3DES)
szOID_RSA_RC4 (CALG_RC4)

If the ContentEncryptionAlgorithm.Parameters.cbData = 0, then, an ASN.1 encoded OCTET STRING containing the IV is automatically generated. The IV is created using CryptGenRandom.

Note, when a message is decrypted, if it has an Initialization Vector parameter, the cryptographic message functions will call CryptSetKeyParam with the Initialization Vector before doing the decrypt.

The szOID_RSA_RC2CBC(CALG_RC2) algorithm requires the Parameters to be encoded as a CRYPT_RC2_CBC_PARAMETERS data structure. If the ContentEncryptionAlgorithm.Parameters.cbData = 0, then, an ASN.1 encoded CRYPT_RC2_CBC_PARAMETERS containing the IV is automatically generated. It defaults to the dwVersion corresponding to the 40 bit length. To override the default 40 bit length, the pvEncryptionAuxInfo member can be updated to point to a CMSG_RC2_AUX_INFO data structure which contains the bit length.

pvEncryptionAuxInfo
pvEncryption points to a CMSG_RC2_AUX_INFO data structure for RC2 encryption or a CMSG_SP3_COMPATIBLE_AUX_INFO data structure for SP3 compatible encryption. For other than RC2 or SP3 compatible encryption, pvEncryptionAuxInfo must be set to NULL.
dwFlags
dwFlags is normally set to zero. However, if the encoded output is to be a CMSG_ENVELOPED inner content of an outer cryptographic message, such as a CMSG_SIGNED message, then, the CRYPT_MESSAGE_BARE_CONTENT_OUT_FLAG must be set. If it is not set, then it will be encoded as an inner content type of CMSG_DATA.
dwInnerContentType
dwInnerContentType is normally set to zero. It needs to be set if the input to be encrypted is the encoded output of another cryptographic message, such as, a CMSG_SIGNED. When set, it's one of the cryptographic message types, for example, CMSG_SIGNED.

See Also

CRYPT_ALGORITHM_IDENTIFIER, CryptEncryptMessage, CryptSignAndEncryptMessage


CRYPT_HASH_MESSAGE_PARA

The CRYPT_HASH_MESSAGE_PARA structure is used for hashing messages.

typedef struct _ CRYPT_HASH_MESSAGE_PARA {
    DWORD                      cbSize;
    DWORD                      dwMsgEncodingType;
    HCRYPTPROV                 hCryptProv;
    CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
    void*                      pvHashAuxInfo;
} CRYPT_HASH_MESSAGE_PARA,        *PCRYPT_HASH_MESSAGE_PARA;

Members

cbSize
Must be set to the size of this data structure.
dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

hCryptProv
Specifies a handle to the cryptographic service provider (CSP) to be used.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

HashAlgorithm
The algorithm for use in generating the hash of a message, for example, szOID_OIWSEC_sha1 or szOID_RSA_MD5.
pvHashAuxInfo
Not currently used, and must be set to NULL.

See Also

CRYPT_ALGORITHM_IDENTIFIER, CryptHashMessage, CryptVerifyDetachedMessageHash, CryptVerifyMessageHash


CRYPT_SIGN_MESSAGE_PARA

The CRYPT_SIGN_MESSAGE_PARA structure is used for signing messages by using the specified signing certificate context.

typedef struct _CRYPT_SIGN_MESSAGE_PARA {
    DWORD                       cbSize;
    DWORD                       dwMsgEncodingType;
    PCCERT_CONTEXT              pSigningCert;
    CRYPT_ALGORITHM_IDENTIFIER  HashAlgorithm;
    void                        *pvHashAuxInfo;
    DWORD                       cMsgCert;
    PCCERT_CONTEXT              *rgpMsgCert;
    DWORD                       cMsgCrl;
    PCCRL_CONTEXT               *rgpMsgCrl;
    DWORD                       cAuthAttr;
    PCRYPT_ATTRIBUTE            rgAuthAttr;
    DWORD                       cUnauthAttr;
    PCRYPT_ATTRIBUTE            rgUnauthAttr;
    DWORD                       dwFlags;
    DWORD                       dwInnerContentType;
} CRYPT_SIGN_MESSAGE_PARA, *PCRYPT_SIGN_MESSAGE_PARA;

Members

cbSize
This member must be set to the size of this data structure.
dwMsgEncodingType
The type of message encoding used. Note that it is always acceptable to specify both the certificate and message encoding types, by combining them with a bitwise OR operation as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

However, it is required only to specify the message encoding here. Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pSigningCert
A pointer to the certificate context to be used in the signing.

Either the CERT_KEY_PROV_INFO_PROP_ID, or CERT_KEY_CONTEXT_PROP_ID property must be set for the pSigningCert. They specify the private signature key to use.

HashAlgorithm
The hashing algorithm used to hash the data to be signed, for example, szOID_OIWSEC_sha1 or szOID_RSA_MD5.
pvHashAuxInfo
Not currently used, and must be set to NULL.
cMsgCert
The number of elements in the array rgpMsgCert. It may be set to zero, indicating that no certificates are to be included in the signed message.
rgpMsgCert
An array of pointers to certificate contexts to be included in the signed message. If the pSigningCert is to be included, then it must also be in the rgpMsgCert array.
cMsgCrl
The number of elements in the array rgpMsgCrl. It may be set to zero, indicating that no CRLs are to be included in the signed message.
rgpMsgCrl
An array of pointers to CRL contexts to be included in the signed message.
cAuthAttr
The number of elements in the array rgAuthAttr.
rgAuthAttr
An array of structures, each holding authenticated attribute information. If no authenticated attributes are present in rgAuthAttr, then cAuthAttr should be zero. If there are authenticated attributes present, then the PKCS #9 standard dictates that there must be at least two attributes present, the content type object identifier, and the hash of the message itself. These attributes are automatically added by the system.
cUnauthAttr
The number of elements in the array rgUnauthAttr.
rgUnauthAttr
An array of structures, each holding unauthenticated attribute information. If no unauthenticated attributes are present in rgUnauthAttr, then cUnauthAttr should be zero. Unauthenticated attributes may be used to contain countersignatures, among other uses.
dwFlags
dwFlags normally is set to zero. However, if the encoded output is to be a CMSG_SIGNED inner content of an outer cryptographic message, such as a CMSG_ENVELOPED message, then the CRYPT_MESSAGE_BARE_CONTENT_OUT_FLAG must be set. If it is not set, then it will be encoded as an inner content type of CMSG_DATA.
dwInnerContentType
dwInnerContentType is normally set to zero. It needs to be set if the input to be signed is the encoded output of another cryptographic message, such as, an CMSG_ENVELOPED message. When set, it's one of the cryptographic message types, for example, CMSG_ENVELOPED.

See Also

CERT_CONTEXT, CRL_CONTEXT, CRYPT_ALGORITHM_IDENTIFIER, CRYPT_ATTRIBUTE, CryptSignAndEncryptMessage, CryptSignMessage


CRYPT_VERIFY_MESSAGE_PARA

The CRYPT_VERIFY_MESSAGE_PARA structure is used to verify signed messages.

typedef struct _CRYPT_VERIFY_MESSAGE_PARA {
    DWORD                             cbSize;
    DWORD                             dwMsgAndCertEncodingType;
    HCRYPTPROV                        hCryptProv;
    PFN_CRYPT_GET_SIGNER_CERTIFICATE  pfnGetSignerCertificate;
    void*                             pvGetArg;
} CRYPT_VERIFY_MESSAGE_PARA,         *PCRYPT_VERIFY_MESSAGE_PARA;

Members

cbSize
This member must be set to the size of the data structure.
dwMsgAndCertEncodingType
Type of encoding used. Note that both a certificate and message encoding type is required to be specified by combining them with a bitwise OR operation, as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.
Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

hCryptProv
Specifies a handle to the cryptographic service provider to be used to verify a signed message. The CSP identified by hCryptProv is used to do hashing and signature verification.

Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, zero should be passed in. Passing in zero causes the default RSA or DSS provider to be acquired before doing hash, signature verification or recipient encryption operations.

pfnGetSignerCertificate
Pointer to the callback function used to get the signer's certificate context. If NULL, the default callback is used. The default callback tries to get the signer certificate context from the message's certificate store.

An application-defined callback function that gets the signer's certificate can be used in place of the default. It gets passed the certificate ID of the signer (its issuer and serial number) and a handle to its cryptographic signed message's certificate store.

pvGetArg
Argument to pass to the callback function. Typically, this gets and verifies the message signer's certificate.
pfnCryptGetSignerCertificateCallback
The following function is a prototype of an application defined callback:
PCCERT_CONTEXT WINAPI CryptGetSignerCertificateCallback (
    void*        pvGetArg                  // in
    DWORD        dwMsgAndCertEncodingType  // in
    PCERT_INFO   pSignerId                 // in
    HCERTSTORE   hMsgCertStore);           // in

If the message doesn't contain any content or signers, then the function is called with pSignerId == NULL.

For a found signer certificate, the function returns a pointer to a read-only CERT_CONTEXT. The returned CERT_CONTEXT is either obtained from a certificate store or was created via CertCreateCertificateContext. For either case, it is freed via CertFreeCertificateContext.

If a certificate for the signer wasn't found, NULL is returned.

Callback Function Parameters

pvGetArg
A pointer to user-defined data passed on to the verification function, as specified in the CRYPT_VERIFY_MESSAGE_PARA structure.
dwMsgAndCertEncodingType
The type of encoding used. Note that both a certificate and message encoding type were specified by combining them with a bitwise OR operation, as shown in the following example:
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING

Currently defined encoding types are shown in the following table.

Encoding type | Value
X509_ASN_ENCODING | 0x00000001
PKCS_7_ASN_ENCODING | 0x00010000

pSignerId
Pointer to a CERT_INFO data structure that contains the issuer and serial number. It may be NULL if there is no content or signers.
hMsgCertStore
Handle to the certificate store containing all the certificates and CRLs in the signed message.
Return Values
A PCCERT_CONTEXT structure if this function succeeded. NULL if this function failed.

See Also

CERT_CONTEXT, CERT_INFO, CryptDecryptAndVerifyMessageSignature, CryptVerifyDetachedMessageSignature, CryptVerifyMessageSignature


OID Support Data Structures

The data structures in this section are used by the OID Support Functions, and can be found in Wincrypt.h.


CRYPT_OID_FUNC_ENTRY

The CRYPT_OID_FUNC_ENTRY structure contains an OID and the starting address of the routine that it correlates to. It is used with CryptInstallOIDFunctionAddress.

typedef struct _CRYPT_OID_FUNC_ENTRY {
    LPCSTR  pszOID;
    void    *pvFuncAddr;
} CRYPT_OID_FUNC_ENTRY, *PCRYPT_OID_FUNC_ENTRY;

Members

pszOID
If the high-order word of the OID is non-zero, pszOID is a pointer to either an OID string, such as "2.5.29.1" or an ASCII string, such as "file". If the high-order word of the OID is zero, the low-order word specifies the numeric identifier to be used as the object identifier.
pvFuncAddr
The starting address of the routine that the OID correlates to.

See Also

CryptInstallOIDFunctionAddress


CRYPT_OID_INFO

The CRYPT_OID_INFO structure is used for finding or registering OID information.

typedef struct _CRYPT_OID_INFO {
    DWORD               cbSize;
    LPCSTR              pszOID;
    LPCWSTR             pwszName;
    DWORD               dwGroupId;
    union {
        DWORD               dwValue;
        ALG_ID              Algid;
        DWORD               dwLength;
    };
    CRYPT_DATA_BLOB     ExtraInfo;
} CRYPT_OID_INFO, *PCRYPT_OID_INFO;
typedef const CRYPT_OID_INFO CCRYPT_OID_INFO, *PCCRYPT_OID_INFO;

Members

cbSize
Must be set to the size of this data structure.
pszOID
The object identifier associated with this OID information.
pwszName
The friendly name associated with the object identifier.
dwGroupId
Specifies the group ID associated with this OID information.

Currently defined group IDs are shown in the following table.
dwGroupId | Value
CRYPT_HASH_ALG_OID_GROUP_ID | 1
CRYPT_ENCRYPT_ALG_OID_GROUP_ID | 2
CRYPT_PUBKEY_ALG_OID_GROUP_ID | 3
CRYPT_SIGN_ALG_OID_GROUP_ID | 4
CRYPT_RDN_ATTR_OID_GROUP_ID | 5
CRYPT_EXT_OR_ATTR_OID_GROUP_ID | 6
CRYPT_ENHKEY_USAGE_OID_GROUP_ID | 7
CRYPT_POLICY_OID_GROUP_ID | 8

dwValue
An arbitrary value associated with this OID information.

Applies for the following values of dwGroupId:

CRYPT_SIGN_ALG_OID_GROUP_ID

Algid
The algorithm identifier associated with this OID information.

Applies for the following values of dwGroupId:

CRYPT_HASH_ALG_OID_GROUP_ID,
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
CRYPT_SIGN_ALG_OID_GROUP_ID

dwLength
The maximum length for the attribute string.

Applies for the following values of dwGroupId:

CRYPT_RDN_ATTR_OID_GROUP_ID

ExtraInfo
Specifies optional extra information for which the find or register of OID information is being performed.

Applies for the following values of dwGroupId:

CRYPT_PUBKEY_ALG_OID_GROUP_ID

CRYPT_SIGN_ALG_OID_GROUP_ID

CRYPT_RDN_ATTR_OID_GROUP_ID

See Also

CryptFindOIDInfo, CryptRegisterOIDInfo, CryptUnregisterOIDInfo


CRYPT_RC2_CBC_PARAMETERS

The CRYPT_RC2_CBC_PARAMETERS structure is used when the object identifier for encryption is szOID_RSA_RC2CBC. It is used in calls to CryptEncodeObject, CryptEncodeObjectEx, CryptDecodeObject CryptDecodeObjectEx using PKCS_RC2_CBC_PARAMETERS.

typedef struct _CRYPT_RC2_CBC_PARAMETERS {
    DWORD               dwVersion;
    BOOL                fIV;            // set if has following IV
    BYTE                rgbIV[8];
} CRYPT_RC2_CBC_PARAMETERS, *PCRYPT_RC2_CBC_PARAMETERS;

Members

dwVersion
Specifies the key length (40, 64 or 128 bits). Note that the values used on the defined constants differ from the lengths specified.

Currently defined values for dwVersion are shown in the following table.
Encoding type | Value
CRYPT_RC2_40BIT_VERSION | 160
CRYPT_RC2_64BIT_VERSION | 120
CRYPT_RC2_128BIT_VERSION | 58

fIV
A Boolean that specifies whether an 8 byte Initialization Vector is contained in rgbIV[8]. Set to TRUE when IV is present.
rgbIV[8]
Contains the 8 byte Initialization Vector, when present.

The IV is encoded as an OCTET_STRING.

CryptEncodeObject and CryptEncodeObjectEx (X500_OCTET_STRING) can be called to create the encoded OCTET_STRING. The ContentEncryptionAlgorithm's Parameters blob is updated to point to this encoded OCTET_STRING.

Note, when a message is decrypted, if it has an IV parameter, then, the cryptographic message functions will call CryptSetKeyParam with the IV before doing the decrypt.

See Also

CMSG_ENVELOPED_ENCODE_INFO, CRYPT_ENCRYPT_MESSAGE_PARA, PKCS_RC2_CBC_PARAMETERS, CryptEncodeObject, CryptSetKeyParam


CRYPT_SMIME_CAPABILITY

The CRYPT_SMIME_CAPABILITY structure is used to specify a single capability and any associated parameters that it has. Single capabilities are grouped together into a list of CRYPT_SMIME_CAPABILITIES which can be used to specify a prioritized list of preference of capabilities.

Note The CRYPT_SMIME_CAPABILITY is part of an internet draft proposal. For a complete definition, see "draft-dusse-s/mime-cert-01.txt" dated May 5, 1997.

typedef struct _CRYPT_SMIME_CAPABILITY {
    LPSTR               pszObjId;
    CRYPT_OBJID_BLOB    Parameters;
} CRYPT_SMIME_CAPABILITY, *PCRYPT_SMIME_CAPABILITY;

Members

pszObjId
Specifies the object identifier for a capability. Capabilities include signature algorithms, symmetric algorithms, and key enciphering algorithms. It also includes a non-algorithm capability which is the preference for signed data.
Parameters
Contains any parameters associated with the specified capability in pszObjId.

Note, for CryptEncodeObject and CryptEncodeObjectEx (X509_ASN_ENCODING), Parameters.cbData == 0 causes the encoded parameters to be omitted and not encoded as a NULL (05 00) as is done when encoding a CRYPT_ALGORITHM_IDENTIFIER. This is per the S/MIME specification for encoding capabilities which requires it to be omitted.

See Also

CRYPT_SMIME_CAPABILITIES


CRYPT_SMIME_CAPABILITIES

The CRYPT_SMIME_CAPABILITIES structure is used to specify a prioritized array of types of capabilities supported by a user. Capabilities include signature algorithms, symmetric algorithms, and key enciphering algorithms. It also includes a non-algorithm capability which is the preference for signed data.

Note The CRYPT_SMIME_CAPABILITIES are part of an internet draft proposal. For a complete definition, see "draft-dusse-s/mime-cert-01.txt" dated May 5, 1997.

typedef struct _CRYPT_SMIME_CAPABILITIES {
    DWORD                   cCapability;
    PCRYPT_SMIME_CAPABILITY rgCapability;
} CRYPT_SMIME_CAPABILITIES, *PCRYPT_SMIME_CAPABILITIES;

Members

cCapability
The count of elements in rgCapability.
rgCapability
Contains a prioritized array of types of capabilities supported by a user.

See Also

CRYPT_SMIME_CAPABILITY


Default CRYPT_OID_INFO Tables by dwGroupId

The following default tables are supplied with predefined entries that cover commonly used key and group ID combinations. These tables can be expanded per user need by adding combinations with CryptRegisterOIDInfo User added combinations can be removed from the tables using CryptUnregisterOIDInfo.

Table by dwGroupId | Description
CRYPT_HASH_ALG_OID_GROUP_ID | Hash Algorithm Table
CRYPT_ENCRYPT_ALG_OID_GROUP_ID | Encryption Algorithm Table
CRYPT_PUBKEY_ALG_OID_GROUP_ID | Public Key Algorithm Table
CRYPT_SIGN_ALG_OID_GROUP_ID | Signature Algorithm Table
CRYPT_RDN_ATTR_OID_GROUP_ID | RDN Attribute Table
CRYPT_EXT_OR_ATTR_OID_GROUP_ID | Extension or Attribute Table
CRYPT_ENHKEY_USAGE_OID_GROUP_ID | Enhanced Key Usage Table
CRYPT_POLICY_OID_GROUP_ID | Policy Table


CRYPT_HASH_ALG_OID_GROUP_ID

For the CRYPT_HASH_ALG_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName | Algid
szOID_OIWSEC_sha1 | L"sha" | CALG_SHA1
szOID_OIWSEC_sha1 | L"sha1" | CALG_SHA1
szOID_OIWSEC_sha | L"sha" | CALG_SHA
szOID_RSA_MD5 | L"md5" | CALG_MD5
szOID_RSA_MD4 | L"md4" | CALG_MD4
szOID_RSA_MD2 | L"md2" | CALG_MD2

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Hash Algorithm Table
//--------------------------------------------------------------------------
#define HASH_ALG_ENTRY(pszOID, pwszName, Algid) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_HASH_ALG_OID_GROUP_ID, Algid, 0, NULL

static CCRYPT_OID_INFO HashAlgTable[] = {
    HASH_ALG_ENTRY(szOID_OIWSEC_sha1, L"sha", CALG_SHA1),
    HASH_ALG_ENTRY(szOID_OIWSEC_sha1, L"sha1", CALG_SHA1),
    HASH_ALG_ENTRY(szOID_OIWSEC_sha, L"sha", CALG_SHA),
    HASH_ALG_ENTRY(szOID_RSA_MD5, L"md5", CALG_MD5),
    HASH_ALG_ENTRY(szOID_RSA_MD4, L"md4", CALG_MD4),
    HASH_ALG_ENTRY(szOID_RSA_MD2, L"md2", CALG_MD2)
};
#define HASH_ALG_CNT (sizeof(HashAlgTable) / sizeof(HashAlgTable[0]))


CRYPT_ENCRYPT_ALG_OID_GROUP_ID

For CRYPT_ENCRYPT_ALG_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName | Algid
szOID_OIWSEC_desCBC | L"des" | CALG_DES
szOID_RSA_DES_EDE3_CBC | L"3des" | CALG_3DES
szOID_RSA_RC2CBC | L"rc2" | CALG_RC2
szOID_RSA_RC4 | L"rc4" | CALG_RC4

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Encryption Algorithm Table
//--------------------------------------------------------------------------
#define ENCRYPT_ALG_ENTRY(pszOID, pwszName, Algid) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_ENCRYPT_ALG_OID_GROUP_ID, \
    Algid, 0, NULL

static CCRYPT_OID_INFO EncryptAlgTable[] = {
    ENCRYPT_ALG_ENTRY(szOID_OIWSEC_desCBC, L"des", CALG_DES),
    ENCRYPT_ALG_ENTRY(szOID_RSA_DES_EDE3_CBC, L"3des", CALG_3DES),
    ENCRYPT_ALG_ENTRY(szOID_RSA_RC2CBC, L"rc2", CALG_RC2),
    ENCRYPT_ALG_ENTRY(szOID_RSA_RC4, L"rc4", CALG_RC4)
};
#define ENCRYPT_ALG_CNT (sizeof(EncryptAlgTable) / sizeof(EncryptAlgTable[0]))


CRYPT_PUBKEY_ALG_OID_GROUP_ID

For the CRYPT_PUBKEY_ALG_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName | Algid | Extra Info
szOID_RSA_RSA | L"RSA" | CALG_RSA_KEYX | N/A
szOID_RSA_RSA | L"RSA_KEYX" | CALG_RSA_KEYX | N/A
szOID_RSA_RSA | L"RSA" | CALG_RSA_SIGN | N/A
szOID_RSA_RSA | L"RSA_SIGN" | CALG_RSA_SIGN | N/A
szOID_OIWSEC_dsa | L"DSA" | CALG_DSS_SIGN | N/A
szOID_OIWSEC_dsa | L"DSS" | CALG_DSS_SIGN | N/A
szOID_OIWSEC_dsa | L"DSA_SIGN" | CALG_DSS_SIGN | N/A
szOID_OIWSEC_rsaXchg | L"RSA_KEYX" | CALG_RSA_KEYX | N/A
szOID_INFOSEC_mosaicKMandUpdSig | L"mosaicKMandUpdSig" | CALG_DSS_SIGN | dwMosaicFlags see Note below

Note For the Extra Info dwMosaicFlags,
static const DWORD dwMosaicFlags = \
CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG;
cbData = sizeof(DWORD);
pbData = (BYTE *) &dwMosaicFlags;

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Public Key Algorithm Table
//--------------------------------------------------------------------------
// CRYPT_PUBKEY_ALG_OID_GROUP_ID has the following optional ExtraInfo:
//  DWORD[0] - Flags. CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG can be set to
//  inhibit the reformatting of the signature before
//  CryptVerifySignature is called or after CryptSignHash
//  is called. CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG can
//   be set to include the public key algorithm's parameters
//   in the PKCS7's digestEncryptionAlgorithm's parameters.

#define CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG     0x1
#define CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG    0x2

static const DWORD dwMosaicFlags = CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG;

#define PUBKEY_ALG_ENTRY(pszOID, pwszName, Algid) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_PUBKEY_ALG_OID_GROUP_ID, \
    Algid, 0, NULL

#define PUBKEY_EXTRA_ALG_ENTRY(pszOID, pwszName, Algid, dwFlags) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_PUBKEY_ALG_OID_GROUP_ID, \
    Algid, sizeof(dwFlags), (BYTE *) &dwFlags

static CCRYPT_OID_INFO PubKeyAlgTable[] = {
    PUBKEY_ALG_ENTRY(szOID_RSA_RSA, L"RSA", CALG_RSA_KEYX),
    PUBKEY_ALG_ENTRY(szOID_RSA_RSA, L"RSA_KEYX", CALG_RSA_KEYX),
    PUBKEY_ALG_ENTRY(szOID_RSA_RSA, L"RSA", CALG_RSA_SIGN),
    PUBKEY_ALG_ENTRY(szOID_RSA_RSA, L"RSA_SIGN", CALG_RSA_SIGN),
    PUBKEY_ALG_ENTRY(szOID_OIWSEC_dsa, L"DSA", CALG_DSS_SIGN),
    PUBKEY_ALG_ENTRY(szOID_OIWSEC_dsa, L"DSS", CALG_DSS_SIGN),
    PUBKEY_ALG_ENTRY(szOID_OIWSEC_dsa, L"DSA_SIGN", CALG_DSS_SIGN),
    PUBKEY_ALG_ENTRY(szOID_OIWSEC_rsaXchg, L"RSA_KEYX", CALG_RSA_KEYX),
    PUBKEY_EXTRA_ALG_ENTRY(szOID_INFOSEC_mosaicKMandUpdSig,
        L"mosaicKMandUpdSig", CALG_DSS_SIGN, dwMosaicFlags)
};
#define PUBKEY_ALG_CNT (sizeof(PubKeyAlgTable) / sizeof(PubKeyAlgTable[0]))


CRYPT_SIGN_ALG_OID_GROUP_ID

For the CRYPT_SIGN_ALG_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName | dwValue | Extra Info see Note below
szOID_OIWSEC_sha1RSASign | L"shaRSA" | CALG_SHA | aiRsaPubKey
szOID_OIWSEC_sha1RSASign | L"sha1RSA" | CALG_SHA | aiRsaPubKey
szOID_OIWSEC_shaRSA | L"shaRSA" | CALG_SHA | aiRsaPubKey
szOID_RSA_MD5RSA | L"md5RSA" | CALG_MD5 | aiRsaPubKey
szOID_OIWSEC_md5RSA | L"md5RSA" | CALG_MD5 | aiRsaPubKey
szOID_RSA_MD2RSA | L"md2RSA" | CALG_MD2 | aiRsaPubKey
szOID_RSA_MD4RSA | L"md4RSA" | CALG_MD4 | aiRsaPubKey
szOID_OIWSEC_md4RSA | L"md4RSA" | CALG_MD4 | aiRsaPubKey
szOID_OIWSEC_md4RSA2 | L"md4RSA" | CALG_MD4 | aiRsaPubKey
szOID_OIWDIR_md2RSA | L"md2RSA" | CALG_MD2 | aiRsaPubKey
szOID_INFOSEC_mosaicUpdatedSig | L"mosaicUpdatedSig" | CALG_SHA | rgdwMosaicSign
szOID_OIWSEC_shaDSA | L"shaDSA" | CALG_SHA | aiDssPubKey
szOID_RSA_SHA1RSA | L"shaRSA" | CALG_SHA | aiRsaPubKey

Note For the Extra Info aiRsaPubKey,
static const ALG_ID aiRsaPubKey = CALG_RSA_SIGN;
cbData = sizeof( aiRsaPubKey);
pbData = (BYTE *) &aiRsaPubKey;

For the Extra Info aiDssPubKey,
static const ALG_ID aiDssPubKey = CALG_DSS_SIGN;
cbData = sizeof( aiDssPubKey );
pbData = (BYTE *) &aiDssPubKey;

For the Extra Info rgdwMosaicSign,
static const DWORD rgdwMosaicSign[] = {CALG_DSS_SIGN,
CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG};
cbData = sizeof( rgdwMosaicSign[]);
pbData = (BYTE *) &rgdwMosaicSign;

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Signature Algorithm Table
//--------------------------------------------------------------------------
static const ALG_ID aiDssPubKey = CALG_DSS_SIGN;
static const ALG_ID aiRsaPubKey = CALG_RSA_SIGN;
static const DWORD rgdwMosaicSign[] = {
    CALG_DSS_SIGN, CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG
};

#define SIGN_ALG_ENTRY(pszOID, pwszName, aiHash, aiPubKey) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_SIGN_ALG_OID_GROUP_ID, aiHash, \
    sizeof(aiPubKey), (BYTE *) &aiPubKey
#define DSS_SIGN_ALG_ENTRY(pszOID, pwszName) \
    SIGN_ALG_ENTRY(pszOID, pwszName, CALG_SHA, aiDssPubKey)
#define RSA_SIGN_ALG_ENTRY(pszOID, pwszName, aiHash) \
    SIGN_ALG_ENTRY(pszOID, pwszName, aiHash, aiRsaPubKey)

#define SIGN_EXTRA_ALG_ENTRY(pszOID, pwszName, aiHash, rgdwExtra) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_SIGN_ALG_OID_GROUP_ID, aiHash, \
    sizeof(rgdwExtra), (BYTE *) rgdwExtra

static CCRYPT_OID_INFO SignAlgTable[] = {
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_sha1RSASign, L"shaRSA", CALG_SHA),
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_sha1RSASign, L"sha1RSA", CALG_SHA),
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_shaRSA, L"shaRSA", CALG_SHA),
    RSA_SIGN_ALG_ENTRY(szOID_RSA_MD5RSA, L"md5RSA", CALG_MD5),
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_md5RSA, L"md5RSA", CALG_MD5),
    RSA_SIGN_ALG_ENTRY(szOID_RSA_MD2RSA, L"md2RSA", CALG_MD2),
    RSA_SIGN_ALG_ENTRY(szOID_RSA_MD4RSA, L"md4RSA", CALG_MD4),
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_md4RSA, L"md4RSA", CALG_MD4),
    RSA_SIGN_ALG_ENTRY(szOID_OIWSEC_md4RSA2, L"md4RSA", CALG_MD4),
    RSA_SIGN_ALG_ENTRY(szOID_OIWDIR_md2RSA, L"md2RSA", CALG_MD2),
    SIGN_EXTRA_ALG_ENTRY(szOID_INFOSEC_mosaicUpdatedSig, L"mosaicUpdatedSig",
        CALG_SHA, rgdwMosaicSign),
    DSS_SIGN_ALG_ENTRY(szOID_OIWSEC_shaDSA, L"shaDSA"),
    RSA_SIGN_ALG_ENTRY(szOID_RSA_SHA1RSA, L"shaRSA", CALG_SHA)
};
#define SIGN_ALG_CNT (sizeof(SignAlgTable) / sizeof(SignAlgTable[0]))


CRYPT_RDN_ATTR_OID_GROUP_ID

For the CRYPT_RDN_ATTR_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName | Extra Info see Note below
szOID_COMMON_NAME | L"CN" | N/A
szOID_LOCALITY_NAME | L"L" | N/A
szOID_ORGANIZATION_NAME | L"O" | N/A
szOID_ORGANIZATIONAL_UNIT_NAME | L"OU" | N/A
szOID_RSA_emailAddr | L"Email" | rgdwIA5ValueType
szOID_COUNTRY_NAME | L"C" | rgdwPrintableValueType
szOID_STATE_OR_PROVINCE_NAME | L"S" | N/A
szOID_STATE_OR_PROVINCE_NAME | L"ST" | N/A
szOID_STREET_ADDRESS | L"STREET" | N/A
szOID_TITLE | L"T" | N/A
szOID_TITLE | L"Title" | N/A
szOID_GIVEN_NAME | L"G" | N/A
szOID_GIVEN_NAME | L"GN" | N/A
szOID_GIVEN_NAME | L"GivenName" | N/A
szOID_INITIALS | L"I" | N/A
szOID_INITIALS | L"Initials" | N/A
szOID_SUR_NAME | L"SN" | N/A
szOID_DEVICE_SERIAL_NUMBER | L"" | rgdwPrintableValueType
szOID_DOMAIN_COMPONENT | L"DC" | rgdwIA5ValueType
szOID_DESCRIPTION | L"" | N/A
szOID_BUSINESS_CATEGORY | L"" | N/A
szOID_POSTAL_CODE | L"" | N/A
szOID_POST_OFFICE_BOX | L"" | N/A
szOID_PHYSICAL_DELIVERY_OFFICE_NAME | L"" | N/A
szOID_TELEPHONE_NUMBER | L"" | rgdwPrintableValueType
szOID_X21_ADDRESS | L"" | rgdwNumericValueType
szOID_INTERNATIONAL_ISDN_NUMBER | L"" | rgdwNumericValueType
szOID_DESTINATION_INDICATOR | L"" | rgdwPrintableValueType

Note For the Extra Info rgdwIA5ValueType,
static const DWORD rgdwIA5ValueType[] =
{ CERT_RDN_IA5_STRING, 0 };
cbData = sizeof( rgdwIA5ValueType);
pbData = (BYTE *) &rgdwIA5ValueType;

For the Extra Info rgdwPrintableValueType,
static const DWORD rgdwPrintableValueType[] = {
CERT_RDN_PRINTABLE_STRING, 0 };
cbData = sizeof( rgdwPrintableValueType);
pbData = (BYTE *) &rgdwPrintableValueType;

For the Extra Info rgdwNumericValueType,
static const DWORD rgdwNumericValueType[] = {
CERT_RDN_NUMERIC_STRING, 0 };
CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG};
cbData = sizeof( rgdwNumericValueType);
pbData = (BYTE *) &rgdwNumericValueType;

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  RDN Attribute Table
//--------------------------------------------------------------------------

// PLEASE UPDATE the following define in certstr.cpp if you add a new entry
// with a longer pwszName
// #define MAX_X500_KEY_LEN    64

// Ordered lists of acceptable RDN attribute value types. 0 terminates.
static const DWORD rgdwPrintableValueType[] = { CERT_RDN_PRINTABLE_STRING, 0 };
static const DWORD rgdwIA5ValueType[] = { CERT_RDN_IA5_STRING, 0 };
static const DWORD rgdwNumericValueType[] = { CERT_RDN_NUMERIC_STRING, 0 };

#define RDN_ATTR_ENTRY(pszOID, pwszName, rgdwValueType) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_RDN_ATTR_OID_GROUP_ID, 0, \
    sizeof(rgdwValueType), (BYTE *) rgdwValueType
#define DEFAULT_RDN_ATTR_ENTRY(pszOID, pwszName) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_RDN_ATTR_OID_GROUP_ID, 0, 0, NULL

static CCRYPT_OID_INFO RDNAttrTable[] = {
    // Ordered with most commonly used key names at the beginning

    // Labeling attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_COMMON_NAME, L"CN"),
    // Geographic attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_LOCALITY_NAME, L"L"),
    // Organizational attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_ORGANIZATION_NAME, L"O"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_ORGANIZATIONAL_UNIT_NAME, L"OU"),

    // Verisign sticks the following in their cert names
    RDN_ATTR_ENTRY(szOID_RSA_emailAddr, L"Email", rgdwIA5ValueType),

    // The following aren't used in Verisign's certs

    // Geographic attribute types:
    RDN_ATTR_ENTRY(szOID_COUNTRY_NAME, L"C", rgdwPrintableValueType),
    DEFAULT_RDN_ATTR_ENTRY(szOID_STATE_OR_PROVINCE_NAME, L"S"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_STATE_OR_PROVINCE_NAME, L"ST"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_STREET_ADDRESS, L"STREET"),

    // Organizational attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_TITLE, L"T"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_TITLE, L"Title"),

    DEFAULT_RDN_ATTR_ENTRY(szOID_GIVEN_NAME, L"G"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_GIVEN_NAME, L"GN"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_GIVEN_NAME, L"GivenName"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_INITIALS, L"I"),
    DEFAULT_RDN_ATTR_ENTRY(szOID_INITIALS, L"Initials"),

    // Labeling attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_SUR_NAME, L"SN"),
    RDN_ATTR_ENTRY(szOID_DEVICE_SERIAL_NUMBER, L"", rgdwPrintableValueType),

    // Pilot user attribute types:
    RDN_ATTR_ENTRY(szOID_DOMAIN_COMPONENT, L"DC", rgdwIA5ValueType),

    // Explanatory attribute types:
    DEFAULT_RDN_ATTR_ENTRY(szOID_DESCRIPTION, L""),
//  szOID_SEARCH_GUIDE                  "2.5.4.14"
    DEFAULT_RDN_ATTR_ENTRY(szOID_BUSINESS_CATEGORY, L""),

    // Postal addressing attribute types:
//  szOID_POSTAL_ADDRESS                "2.5.4.16"
    DEFAULT_RDN_ATTR_ENTRY(szOID_POSTAL_CODE, L""),
    DEFAULT_RDN_ATTR_ENTRY(szOID_POST_OFFICE_BOX, L""),
    DEFAULT_RDN_ATTR_ENTRY(szOID_PHYSICAL_DELIVERY_OFFICE_NAME, L""),

    // Telecommunications addressing attribute types:
    RDN_ATTR_ENTRY(szOID_TELEPHONE_NUMBER, L"", rgdwPrintableValueType),
//  szOID_TELEX_NUMBER                  "2.5.4.21"
//  szOID_TELETEXT_TERMINAL_IDENTIFIER  "2.5.4.22"
//  szOID_FACSIMILE_TELEPHONE_NUMBER    "2.5.4.23"
    RDN_ATTR_ENTRY(szOID_X21_ADDRESS, L"", rgdwNumericValueType),
    RDN_ATTR_ENTRY(szOID_INTERNATIONAL_ISDN_NUMBER, L"", rgdwNumericValueType),
//  szOID_REGISTERED_ADDRESS            "2.5.4.26"
    RDN_ATTR_ENTRY(szOID_DESTINATION_INDICATOR, L"", rgdwPrintableValueType)

    // Preference attribute types:
//  szOID_PREFERRED_DELIVERY_METHOD     "2.5.4.28"

    // OSI application attribute types:
//  szOID_PRESENTATION_ADDRESS          "2.5.4.29"
//  szOID_SUPPORTED_APPLICATION_CONTEXT "2.5.4.30"

    // Relational application attribute types:
//  szOID_MEMBER                        "2.5.4.31"
//  szOID_OWNER                         "2.5.4.32"
//  szOID_ROLE_OCCUPANT                 "2.5.4.33"
//  szOID_SEE_ALSO                      "2.5.4.34"

    // Security attribute types:
//  szOID_USER_PASSWORD                 "2.5.4.35"
//  szOID_USER_CERTIFICATE              "2.5.4.36"
//  szOID_CA_CERTIFICATE                "2.5.4.37"
//  szOID_AUTHORITY_REVOCATION_LIST     "2.5.4.38"
//  szOID_CERTIFICATE_REVOCATION_LIST   "2.5.4.39"
//  szOID_CROSS_CERTIFICATE_PAIR        "2.5.4.40"

    // Undocumented attribute types???
//#define szOID_???                         "2.5.4.41"
};
#define RDN_ATTR_CNT (sizeof(RDNAttrTable) / sizeof(RDNAttrTable[0]))


CRYPT_EXT_OR_ATTR_OID_GROUP_ID

For the CRYPT_EXT_OR_ATTR_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName
szOID_AUTHORITY_KEY_IDENTIFIER2 | L"Authority Key Identifier"
szOID_AUTHORITY_KEY_IDENTIFIER | L"Authority Key Identifier"
szOID_KEY_ATTRIBUTES | L"Key Attributes"
szOID_KEY_USAGE_RESTRICTION | L"Key Usage Restriction"
szOID_SUBJECT_ALT_NAME2 | L"Subject Alternative Name"
szOID_SUBJECT_ALT_NAME | L"Subject Alternative Name"
szOID_ISSUER_ALT_NAME2 | L"Issuer Alternative Name"
szOID_ISSUER_ALT_NAME | L"Issuer Alternative Name"
szOID_BASIC_CONSTRAINTS2 | L"Basic Constraints"
szOID_BASIC_CONSTRAINTS | L"Basic Constraints"
szOID_KEY_USAGE | L"Key Usage"
szOID_CERT_POLICIES | L"Certificate Policies"
szOID_SUBJECT_KEY_IDENTIFIER | L"Subject Key Identifier"
szOID_CRL_REASON_CODE | L"CRL Reason Code"
szOID_CRL_DIST_POINTS | L"CRL Distribution Points"
szOID_ENHANCED_KEY_USAGE | L"Enhanced Key Usage"
szOID_CERT_EXTENSIONS | L"Certificate Extensions"
szOID_NEXT_UPDATE_LOCATION | L"Next Update Location"
szOID_YESNO_TRUST_ATTR | L"Yes or No Trust"
szOID_RSA_emailAddr | L"Email Address"
szOID_RSA_unstructName | L"Unstructured Name"
szOID_RSA_contentType | L"Content Type"
szOID_RSA_messageDigest | L"Message Digest"
szOID_RSA_signingTime | L"Signing Time"
szOID_RSA_counterSign | L"Counter Sign"
szOID_RSA_challengePwd | L"Challenge Password"
szOID_RSA_unstructAddr | L"Unstructured Addresss"
szOID_RSA_extCertAttrs | L""
szOID_RSA_S/MIMECapabilities | L"S/MIME Capabilities"
szOID_RSA_preferSignedData | L"Prefer Signed Data"

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Extension or Attribute Table
//--------------------------------------------------------------------------
#define EXT_ATTR_ENTRY(pszOID, pwszName) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_EXT_OR_ATTR_OID_GROUP_ID, 0, 0, NULL

static CCRYPT_OID_INFO ExtAttrTable[] = {
    EXT_ATTR_ENTRY(szOID_AUTHORITY_KEY_IDENTIFIER2,
        L"Authority Key Identifier"),
    EXT_ATTR_ENTRY(szOID_AUTHORITY_KEY_IDENTIFIER, L"Authority Key Identifier"),
    EXT_ATTR_ENTRY(szOID_KEY_ATTRIBUTES, L"Key Attributes"),
    EXT_ATTR_ENTRY(szOID_KEY_USAGE_RESTRICTION, L"Key Usage Restriction"),
    EXT_ATTR_ENTRY(szOID_SUBJECT_ALT_NAME2, L"Subject Alternative Name"),
    EXT_ATTR_ENTRY(szOID_SUBJECT_ALT_NAME, L"Subject Alternative Name"),
    EXT_ATTR_ENTRY(szOID_ISSUER_ALT_NAME2, L"Issuer Alternative Name"),
    EXT_ATTR_ENTRY(szOID_ISSUER_ALT_NAME, L"Issuer Alternative Name"),
    EXT_ATTR_ENTRY(szOID_BASIC_CONSTRAINTS2, L"Basic Constraints"),
    EXT_ATTR_ENTRY(szOID_BASIC_CONSTRAINTS, L"Basic Constraints"),
    EXT_ATTR_ENTRY(szOID_KEY_USAGE, L"Key Usage"),
    EXT_ATTR_ENTRY(szOID_CERT_POLICIES, L"Certificate Policies"),
    EXT_ATTR_ENTRY(szOID_SUBJECT_KEY_IDENTIFIER, L"Subject Key Identifier"),
    EXT_ATTR_ENTRY(szOID_CRL_REASON_CODE, L"CRL Reason Code"),
    EXT_ATTR_ENTRY(szOID_CRL_DIST_POINTS, L"CRL Distribution Points"),
    EXT_ATTR_ENTRY(szOID_ENHANCED_KEY_USAGE, L"Enhanced Key Usage"),
    EXT_ATTR_ENTRY(szOID_CERT_EXTENSIONS, L"Certificate Extensions"),
    EXT_ATTR_ENTRY(szOID_NEXT_UPDATE_LOCATION, L"Next Update Location"),
    EXT_ATTR_ENTRY(szOID_YESNO_TRUST_ATTR, L"Yes or No Trust"),
    EXT_ATTR_ENTRY(szOID_RSA_emailAddr, L"Email Address"),
    EXT_ATTR_ENTRY(szOID_RSA_unstructName, L"Unstructured Name"),
    EXT_ATTR_ENTRY(szOID_RSA_contentType, L"Content Type"),
    EXT_ATTR_ENTRY(szOID_RSA_messageDigest, L"Message Digest"),
    EXT_ATTR_ENTRY(szOID_RSA_signingTime, L"Signing Time"),
    EXT_ATTR_ENTRY(szOID_RSA_counterSign, L"Counter Sign"),
    EXT_ATTR_ENTRY(szOID_RSA_challengePwd, L"Challenge Password"),
    EXT_ATTR_ENTRY(szOID_RSA_unstructAddr, L"Unstructured Addresss"),
    EXT_ATTR_ENTRY(szOID_RSA_extCertAttrs, L""),
    EXT_ATTR_ENTRY(szOID_RSA_SMIMECapabilities, L"SMIME Capabilities"),
    EXT_ATTR_ENTRY(szOID_RSA_preferSignedData, L"Prefer Signed Data")
};
#define EXT_ATTR_CNT (sizeof(ExtAttrTable) / sizeof(ExtAttrTable[0]))


CRYPT_ENHKEY_USAGE_OID_GROUP_ID

For the CRYPT_ENHKEY_USAGE_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName
szOID_PKIX_KP_SERVER_AUTH | L"Server Authentication"
szOID_PKIX_KP_CLIENT_AUTH | L"Client Authentication"
szOID_PKIX_KP_CODE_SIGNING | L"Code Signing"
szOID_PKIX_KP_EMAIL_PROTECTION | L"Email Protection"
szOID_KP_CTL_USAGE_SIGNING | L"Trust List Signing"

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Enhanced Key Usage Table
//--------------------------------------------------------------------------
#define ENHKEY_ENTRY(pszOID, pwszName) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_ENHKEY_USAGE_OID_GROUP_ID, 0, 0, NULL

static CCRYPT_OID_INFO EnhKeyTable[] = {
    ENHKEY_ENTRY(szOID_PKIX_KP_SERVER_AUTH, L"Server Authentication"),
    ENHKEY_ENTRY(szOID_PKIX_KP_CLIENT_AUTH, L"Client Authentication"),
    ENHKEY_ENTRY(szOID_PKIX_KP_CODE_SIGNING, L"Code Signing"),
    ENHKEY_ENTRY(szOID_PKIX_KP_EMAIL_PROTECTION, L"Email Protection"),
    ENHKEY_ENTRY(szOID_KP_CTL_USAGE_SIGNING, L"Trust List Signing")
};
#define ENHKEY_CNT (sizeof(EnhKeyTable) / sizeof(EnhKeyTable[0]))


CRYPT_POLICY_OID_GROUP_ID

For the CRYPT_POLICY_OID_GROUP_ID, the following predefined entries exist. Note that the varying members of the CRYPT_OID_INFO structure for this group are shown in the table. These correspond to the find criteria that should be used for this group when making calls to CryptFindOIDInfo. The values for members that do not vary for entries in this group are typically set to zero, or NULL, except that cbSize which always is set to the size of CRYPT_OID_INFO, and the dwGroupId always is set to this group.

pszOID | pwszName
szOID_ | L""

The C code used to populate the table (an array of CCRYPT_OID_INFO structures) is shown below.

C code specifying table.

//+-------------------------------------------------------------------------
//  Policy Table
//--------------------------------------------------------------------------
#define POLICY_ENTRY(pszOID, pwszName) \
    OID_INFO_LEN, pszOID, pwszName, CRYPT_POLICY_OID_GROUP_ID, 0, 0, NULL

static CCRYPT_OID_INFO PolicyTable[] = {
    POLICY_ENTRY(szOID_, L"")
};
#define POLICY_CNT (sizeof(PolicyTable) / sizeof(PolicyTable[0]))

#endif


A

Abstract Syntax Notation One
(ASN.1) A method used to specify abstract objects that are intended for serial transmission.

ASN.1 is defined in CCITT Recommendation X.208.

access block
A key blob that contains the key of the symmetric cipher used to encrypt a file or message.

The access block can only be opened with a private key.

ALG_CLASS_HASH
The CryptoAPI algorithm class for hashing algorithms.

Typical hashing algorithms include MD2, MD5, SHA-1, and MAC.

ALG_CLASS_DATA_ENCRYPT
The CryptoAPI algorithm class for data encryption algorithms.

Typical data encryption algorithms include RC2 and RC4.

ALG_CLASS_KEY_EXCHANGE
The CryptoAPI algorithm class for key exchange algorithms.

A typical key exchange algorithm is RSA_KEYX.

ALG_CLASS_SIGNATURE
The CryptoAPI algorithm class for signature algorithms.

A typical digital signature algorithm is RSA_SIGN.

application protocol
A protocol that normally resides on top of the transport layer. For example, HTTP, TELNET, FTP, and SMTP are all application protocols.
ASN.1
See Abstract Syntax Notation One.
asymmetric algorithm
See public-key algorithm.
attribute
An element of a relative distinguished name (RDN). Some typical attributes include common name, surname, e-mail address, street address, and country name.

With respect to the CryptoAPI, each attribute is defined by a CERT_RDN_ATTR structure.

attribute blob
An encoded representation of the attribute information stored in a certificate request.
authenticate
To determine the identity of the entity that signed a message (entity authentication), or to verify that a message was not altered (data authentication).


B

backup authority
A trusted application running on a secure computer that provides secondary storage for the session keys of its clients.

The backup authority stores session keys as key blobs that are encrypted with the backup authority's public key.

base content type
A type of data contained in a PKCS #7 message. Base content types only contain data, no cryptographic enhancements such as hashes or signatures.

Currently, the only base content type is the Data content type.

base cryptographic functions
The lowest level of functions in the CryptoAPI architecture. They are used by applications and other high-level CryptoAPI functions to provide access to CSP-provided cryptographic algorithms, secure key generation, and secure storage of secrets.

See also cryptographic service providers.

Basic Encoding Rules
(BER) The set of rules used to encode ASN.1 defined data into a stream of bits (zeros or ones) for external storage or transmission. A single ASN.1 object may have several equivalent BER encodings.

BER is defined in CCITT Recommendation X.209. This is one of the two encoding methods currently used by the CryptoAPI.

BER
See Basic Encoding Rules.
blob
A generic sequence of bits that contain one or more fixed-length header structures plus context specific data.

See also key blobs, certificate blobs, certificate name blobs, and attribute blobs.

block cipher
A cipher algorithm that encrypts data in discrete units (called blocks), rather than as a continuous stream of bits. The most common block size is 64 bits. For example, DES is a block cipher.

Block ciphers are considered more secure than stream ciphers; however, block ciphers tend to execute much slower.

See also stream cipher.


C

CA
See Certification Authority.
CALG_DH_EPHEM
The CryptoAPI algorithm identifier for the Diffie-Hellman key-exchange algorithm when used for the generation of ephemeral keys.

See also Diffie-Hellman (ephemeral) key-exchange algorithm.

CALG_DH_SF
The CryptoAPI algorithm identifier for the Diffie-Hellman key-exchange algorithm when used for the generation of store-and-forward keys.

See also Diffie-Hellman (store and forward) key-exchange algorithm.

CALG_HMAC
The CryptoAPI algorithm identifier for the Hash-Based Message Authentication Code algorithm.

See also HMAC.

CALG_MAC
The CryptoAPI algorithm identifier for the Message Authentication Code algorithm.

See also Message Authentication Code algorithm.

CALG_MD2
The CryptoAPI algorithm identifier for the MD2 hash algorithm.

See also MD2 algorithm.

CALG_MD5
The CryptoAPI algorithm identifier for the MD5 hash algorithm.

See also MD5 algorithm.

CALG_RC2
The CryptoAPI algorithm identifier for the RC2 block cipher algorithm.

See also RC2 block algorithm.

CALG_RC4
The CryptoAPI algorithm identifier for the RC4 stream cipher algorithm.

See also RC4 stream algorithm.

CALG_RSA_KEYX
The CryptoAPI algorithm identifier for the RSA public-key algorithm when used for key exchange.

See also RSA public-key algorithm.

CALG_RSA_SIGN
The CryptoAPI algorithm identifier for the RSA public-key algorithm when used to generate digital signatures. See also RSA public-key algorithm.
CALG_SHA
The CryptoAPI algorithm identifier for the Secure Hash Algorithm (SHA-1).

See also Secure Hash Algorithm.

CAST
A family of DES-like symmetric block ciphers developed by C. M. Adams and S. E. Tavares.

PROV_MS_EXCHANGE provider types specify a particular CAST algorithm that uses a 64-bit block size.

CBC
See Cipher Block Chaining.
certificate
A digitally signed statement that contains information about an entity and the entity's public key, thus binding these two pieces of information together. A certificate is issued by a trusted organization (or entity) called a Certification Authority (CA) after the CA has verified that the entity is who it says it is.

Certificates can contain different types of data. For example, an X.509 certificate includes the format of the certificate, the serial number of the certificate, the algorithm used to sign the certificate, the name of the CA that issued the certificate, the name and public key of the entity requesting the certificate, and the CA's signature.

Certification Authority
(CA) A trusted organization or entity that issues certificates for authentication purposes. Before issuing the certificate the CA first authenticates the entity requesting the certificate, then issues a certificate that includes information about the requester, including the requester's public key.
certificate blob
A blob containing the certificate data.

A certificate blob is created by calls to CryptEncodeObject. The process is complete when the output of the call contains all the certificate data.

certificate context
A CERT_CONTEXT structure that contains a handle to a certificate store, a pointer to the original encoded certificate blob, a pointer to a CERT_INFO structure, and an encoding type member. It is the CERT_INFO structure that contains most of the certificate information.
certificate encode/decode functions
Functions that manage the translation of certificates and related material into standard, binary formats that can be used in different environments.
certificate encoding type
Defines how the certificate is encoded. The certificate encoding type is stored in the low-order word of the encoding type (DWORD) structure.
certificate name blob
An encoded representation of the name information that is included in certificates. Each name blob is mapped to a CERT_NAME_BOLB structure.

For example, the issuer and subject information referenced by a CERT_INFO structure is stored in two CERT_NAME_BLOB structures.

certificate request
A specially formatted electronic message (sent to a CA) used to request a certificate. The request must contain the information required by the CA to authenticate the request, plus the public key of the entity requesting the certificate.

All the information necessary to create the request is mapped to a CERT_REQUEST_INFO structure.

Certificate Revocation List
(CRL) A list maintained and published by a CA that contains those certificates that have been revoked by the CA.
Certificate Server
A server that issues certificates for a particular CA. The certificate server software provides customizable services for issuing and managing certificates used in security systems employing public-key cryptography.

Microsoft Certificate Server performs a central role in the management of software security systems to enable secure communications across the Internet, corporate intranets, and other networks that are not secure.

certificate store
Typically, a permanent storage where certificates, certificate request lists (CRLs), and certificate trust lists (CTLs) are stored. It is possible, however, to create and open a certificate store solely in memory when working with certificates that do not need to be put in permanent storage.

The certificate store is central to much of the certificate functionality in the CryptoAPI.

certificate store functions
Functions that manage the storage and retrieval data such as certificates, certificate request lists (CRLs), and certificate trust lists (CTLs).

These functions can be separated into common certificate functions, certificate revocation list functions, and certificate trust list functions.

certificate trust list
(CTL) A predefined list of items that have been signed by a trusted entity. A CTL can be anything, such as a list of hashes of certificates, or a list of file names. All the items in the list are authenticated (approved) by the signing entity.
CFB
See Cipher Feedback.
chaining mode
A block cipher mode that introduces feedback by combining ciphertext and plaintext.

See also Cipher Block Chaining.

cipher
A cryptographic algorithm used to encrypt data, to transform plaintext into ciphertext using a predefined key.
Cipher Block Chaining
(CBC) A method of operating a symmetric block cipher that uses feedback to combine previously generated ciphertext with new plaintext.

Each plaintext block is combined with the ciphertext of the previous block by a bitwise XOR before it is encrypted. Combining ciphertext and plaintext ensures that even if the plaintext contains many identical blocks, they will each encrypt to a different ciphertext block.

When the Microsoft Base Cryptographic Provider is used, CBC is the default cipher mode.

Cipher Block Chaining (CBC) MAC
A block cipher method that encrypts the base data with a block cipher and then uses the last encrypted block as the hash value. The encryption algorithm used to build the MAC is the one that was specified when the session key was created.
Cipher Feedback
(CFB) A block cipher mode that processes small increments of plaintext into ciphertext, instead of processing an entire block at a time.

This mode uses a shift register that is one block size in length and divided into sections. For example, if the block size is 64 bits with eight bits processed at a time, then the shift register would be divided into eight sections.

cipher mode
A block cipher mode (each block is encrypted individually) that can be specified via the CryptSetKeyParam function. If the application does not explicitly specify one of these modes, then the cipher block chaining (CBC) cipher mode is used.

ECB: A block cipher mode that uses no feedback.

CBC: A block cipher mode that introduces feedback by combining ciphertext and plaintext.

CFB: A block cipher mode that processes small increments of plaintext into ciphertext, instead of processing an entire block at a time.

OFB: A block cipher mode that uses feedback similar to CFB.

ciphertext
A message that has been encrypted.
client
The application, rather than the server application, that initiates a connection to a server.

Compare with server.

cleartext
See plaintext.
communication protocol
The method in which data is serialized (converted to a string of ones and zeros) and deserialized. The protocol is controlled by both software and data-transmission hardware.

Typically discussed in terms of layers, a simplified communication protocol might consist of an application layer, encode/decode layer, and hardware layer.

context function
Functions used to connect to a cryptographic service provider (CSP). These functions enable applications to choose a specific CSP by name, or get one with a needed class of functionality.
countersignature
A signature added to an existing signature in a message. A countersignature is used to sign an existing signature's encrypted hash or time stamp a message.

A countersignature is added by calling CryptMsgCountersign or CryptCountersignEncoded.

CRL
See Certificate Revocation List.
CRYPT_ASN_ENCODING
Specifies certificate encoding. Certificate encoding types are stored in the low-order word of a DWORD (value is: 0x00000001).

Functionally the same as X509_ASN_ENCODING.

cryptoanalysis
Cryptoanalysis is the art and science of breaking ciphertext. In contrast, the art and science of keeping messages secure is cryptography.
Cryptographic API
The Microsoft® Cryptographic API (CryptoAPI) enables application developers to add authentication, encoding, and encryption to their Win32®-based applications. Application developers can use functions in the CryptoAPI without knowing anything about the underlying implementation, in much the same way as they can use a graphics library without knowing anything about the particular graphics hardware configuration.
cryptographic algorithm
A mathematical function used for encryption and decryption. Most cryptographic algorithms are based on a substitution cipher, a transposition cipher, or a combination of both.
cryptographic key
The session (symmetric) key used during the encryption and decryption processes, and the public and private keys used during the authentication process. Of these three keys, the session key and private key must always remain secret.
cryptographic service provider
(CSP) An independent software module that contains cryptography algorithms or services that are integrated into the CryptoAPI. At a minimum, a CSP consists of a dynamic-link library (DLL) and a signature file.

Many CSPs are Microsoft® Win32® application programming interface (API) service programs, managed by the Win32 service control manager.

cryptography
The art and science of keeping messages secure. In contrast, cryptoanalysis is the art and science of breaking a secure message.
cryptology
The branch of mathematics that encompasses both cryptography and cryptoanalysis.
CSP
See cryptographic service provider.
CSP family
A unique group of CSPs that use the same set of data formats and perform their function in the same way. Even when two CSP families use the same algorithm (for example, the RC2 block cipher), their different padding schemes, keys lengths, or default modes make each group distinct.

The CryptoAPI has been designed so that each CSP type represents a particular family.

CSP name
The textual name of the CSP. If the CSP has been signed by Microsoft, this name must exactly match the CSP name that was specified in the Export Compliance Certificate (ECC).
CSP type
Indicates the CSP family associated with a provider. When an application connects to a CSP of a particular type, each of the CryptoAPI functions will, by default, operate in a way prescribed by the family that corresponds to that CSP type.
CTL
See certificate trust list.


D

data content type
A base content type defined by PKCS #7. Data content is simply an octet (byte) string.
data encryption
The process where a plaintext message is scrambled to appear as random gibberish and is difficult to unscramble without a secret key.

Here the term "message" refers to any piece of data designated for encryption; ASCII text, a database file, or other data designated for secure transmission. Plaintext refers to data that has not been encrypted.

data encryption function
A function used to encrypt or decrypt a message. As a set, these functions include support for simultaneously encrypting and decrypting data.
Data Encryption Standard
(DES) A block cipher that encrypts data in 64-bit blocks. DES is a symmetric algorithm that uses the same algorithm and key for encryption and decryption.

Developed in the early 1970s, DES is also known as the DEA (Data Encryption Algorithm) by ANSI and the DEA-1 by ISO.

decoding
The process of translating an encoded object (such as a certificate) or data back to its original format.

In general terms, data is decoded by the Encoding/Decoding layer of the communication protocol. Certificates are decoded by a call to CryptDecodeObject.

decryption
The process in which ciphertext is converted to plaintext.
default mode
Default settings, such as the block encryption cipher mode or the block encryption padding method.
DER
See Distinguished Encoding Rules.
derived key
A cryptographic key created by a call to CryptDeriveKey. A derived key can be created from a password, or any other user data.

Derived keys allow applications to create session keys as needed, eliminating the need to store a particular key.

DES
See Data Encryption Standard.
DH
See Diffie-Hellman algorithm.
DH_KEYX
The CryptoAPI algorithm name for the Diffie-Hellman key-exchange algorithm.

See also Diffie-Hellman algorithm.

Diffie-Hellman algorithm
(DH) A public-key algorithm used for secure key exchange. Diffie-Hellman cannot be used for data encryption.

This algorithm is specified as the key exchange algorithm for PROV_DSS_DH provider types.

See also Diffie-Hellman (store and forward) key-exchange algorithm and Diffie-Hellman (ephemeral) key-exchange algorithm.

Diffie-Hellman (store and forward) key-exchange algorithm
A Diffie-Hellman algorithm where the exchange key values are retained (in the CSP) after the key handle has been destroyed.

See also Diffie-Hellman (ephemeral) key-exchange algorithm.

Diffie-Hellman (ephemeral) key-exchange algorithm
A Diffie-Hellman algorithm where the exchange key value is purged from the CSP when the key handle is destroyed.

See also Diffie-Hellman (store and forward) key-exchange algorithm.

digested data
A data content type defined by PKCS #7 that consists of any type of data plus a message hash (digest) of the content.
digital certificate
See certificate.
digital envelope
Private messages encrypted using the recipient's public key. Enveloped messages can only be decrypted by using the recipient's private key, allowing only the recipient to understand the message.
digital signature
A digital string that is bundled with the message or transmitted separately. They are used to authenticate messages. A valid digital signature confirms that the message has not been tampered with, and may also identify the entity who signed the message. Signing a message does not alter the message itself.
Digital Signature Algorithm
(DSA) A public-key algorithm specified by Digital Signature Standard (DSS). DSA is only used to generate digital signatures. It cannot be used for data encryption.
digital signature key pair
See signature key pair.
Digital Signature Standard
(DSS) A standard that specifies the Digital Signature Algorithm (DSA) for its signature algorithm and SHA-1 as its message hash algorithm. DSA is a public-key cipher that is only used to generate digital signatures and cannot be used for data encryption.

DSS is specified by PROV_DSS, PROV_DSS_DH, and PROV_FORTEZZA provider types.

Distinguished Encoding Rules
(DER) A set of rules for encoding ASN.1 defined data as a stream of bits for external storage or transmission. Every ASN.1 object has exactly one corresponding DER encoding. DER is defined in CCITT Recommendation X.509, Section 8.7. This is one of two encoding methods currently used by the CryptoAPI.
DLL
See dynamic-link library.
DSA
See Digital Signature Algorithm.
DSS
See Digital Signature Standard.
dynamic-link library
A file that contains executable routines that can be called from other applications.


E

ECB
See Electronic Codebook.
Electronic Codebook
(ECB) A block cipher mode (each block is encrypted individually) that uses no feedback. This means any blocks of plaintext that are identical (either in the same message or in a different message that is encrypted with the same key) is transformed into identical ciphertext blocks.

Initialization vectors cannot be used with this cipher mode.

If a single bit of the ciphertext block is garbled, then the entire corresponding plaintext block is also garbled.

encoding
The process of turning data into a stream of bits. Encoding is part of the serialization process that converts data into a stream of ones and zeros so that it can be transmitted over a serial line.
encoding type
Refers to which type of encoding is used for certificate and message encoding. The encoding types are specified as a DWORD, with the type of certificate encoding stored in the low-order word and the type of message encoding stored in the high-order word.

Although some functions or structure fields require only one of the encoding types, it is always acceptable to specify both.

encryption
The process in which data (plaintext) is translated into something that appears to be random and meaningless (ciphertext).
encrypted data
Data that has been converted from plaintext into ciphertext. Encrypted messages are used to disguise the content of a message when it is sent or stored.
encryption and decryption functions
A simplified message function used to encode and encrypt (or decode and decrypt) messages and data.

See also simplified message functions.

enhanced content type
A class of data contained in a PKCS #7 message that contains data (possibly encrypted), plus cryptographic enhancements such as hashes or signatures.

Types of enhanced data defined by PKCS #7 include signed data, enveloped data, signed-and-enveloped data, and digested (hashed) data.

enveloped data content type
A PKCS #7 enhanced content that consists of encrypted content (of any type) and content-encryption keys (for one or more recipients). The combination of encrypted content and encryption key for a recipient is called a digital envelope for that recipient.

This type of message should be used when you want to keep the contents of the message secret and allow only specified persons or entities to retrieve the contents.

exchange key
See exchange key pair.
exchange key pair
A public/private key pair used to encrypt session keys so that they can be safely stored and exchanged with other users. Exchange key pairs are created by calling CryptGenKey.

Compare signature key pair.

external store
A certificate store that maintains its certificates, CRLs, and CTLs in a location external to cached memory, such as in a database on a network server.

An external store does not read and decode its certificates, CRLs, and CTL when CertOpenStore is called. Reading and decoding is deferred until an enumeration or find.


G

GDI
See Graphics Device Interface.
Graphics Device Interface
The executable program that processes graphical function calls from a Windows®-based application and passes those calls to the appropriate device driver, which performs the hardware-specific functions that generate output.


H

handle
A token used to identify or access an object, such as the handle to a cryptographic provider, certificate store, message, or key pair.
hash
A hash is a fixed-size result obtained by applying a mathematical function (the "hashing algorithm") to an arbitrary amount of data.

A good hash function has a quality where changes in the input data can change every bit in the resulting hash value; for this reason hashes are useful in detecting any modification in a large data object, such as a message.

Furthermore, a good hash function has the quality where that it is computationally in-feasible to construct two independent inputs that have the same hash.

See also hashing functions.

hash object
An object used to hash messages or session keys. The hash object is created by a call to CryptCreateHash. The definition of the object is defined by the CSP specified in the call.
hash value
See hash.
hashing algorithm
An algorithm used to produce a hash value of some piece of data, such as a message or session key. Typical hashing algorithms include MD2, MD4, MD5, and SHA-1.
hashing functions
A set of functions used to create and destroy hash objects, get or set the parameters of a hash object, and hash data and session keys.
HMAC
The CryptoAPI algorithm name for the Hash-based Message Authentication Code algorithm when used with a specified hash algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_HMAC) and class (ALG_CLASS_HASH).

See also Message Authentication Code algorithm.

Hash-Based Message Authentication Code
(HMAC) A keyed hashing algorithm implemented by Microsoft cryptographic service providers. It is a more complex algorithm than the simple CBC MAC algorithm because it uses a secret symmetric key to create the hash.

It can be used with any iterated cryptographic hash algorithm, such as MD5 or SHA-1.


I

initialization vector
(IV) A sequence of random bytes appended to the front of the plaintext before encryption by a block cipher. Adding the initialization vector to the beginning of the plaintext eliminates the possibility of having the initial ciphertext block the same for any two messages.

For example, if messages always start with a common header (a letterhead or "From" line) their initial ciphertext would always be the same, assuming that the same cryptographic algorithm and symmetric key was used. Adding a random initialization vector eliminates this from happening.

inner data
Any encoded data used as the message for another encoded message. For example, an enveloped message and its hash value may be the inner data for a second message.
inner content
Data that is enhanced, such as with a digital signature. This term is used primarily when discussing enhanced data in a PKCS #7 message.
integrity
The completeness and accuracy of a message after it has been sent or stored.
IV
See initialization vector.


K

KCA
See Key Certification Authority.
KEA
See Key Exchange Algorithm.
key blob
A blob containing an encrypted private key. Key blobs provide a way to store keys outside the CSP.

Key blobs are created by exporting an existing key from the CSP by calling CryptExportKey. Later, the key blob can be imported into a provider (often a different CSP on a different computer) by calling CryptImportBlob. This creates a key in the CSP that is a duplicate of the one that was exported.

See also simple key blob, public key blob, and private key blob.

key blob format
The format of the key blob when a public or session key is exported from a CSP. The format is specified by the provider type of the exporting CSP. A key blob is created by calling CryptExportKey.

See also public key blob and simple key blob.

Key Certification Authority
(KCA) A trusted entity that typically keeps a secure database of compound messages signed with the KCA's private key. In practical implementations, the compound messages consist of the user's name, the user's public key, and any other important information about the user.

When the receiving application gets a signed message from a user, the application can then verify the public key received with the message by comparing it to the public key stored in the KCA database.

key container
A part of the key database that contains all the key pairs (exchange and signature key pairs) belonging to a specific user.

Each container has a unique name that is used when calling CryptAcquireContext to get a handle to the container.

key database
A database that contains the persistent cryptographic keys for a specific CSP. The database contains one or more key containers, which individually store all the cryptographic key pairs for a specific user.

See also key container.

key exchange algorithm
An algorithm used to encrypt and decrypt exchange keys (symmetric session keys). Some common key exchange algorithms include DH and KEA.

Each provider type can specify only one key exchange algorithm.

Key Exchange Algorithm
(KEA) The key exchange algorithm specified by a PROV_FORTEZZA provider type. This algorithm is an improved version of the Diffie-Hellman algorithm.
key exchange functions
A set of functions used to exchange or transmit keys. Key exchange functions can also be used to implement fully authenticated three-phase key exchanges.
key-exchange key pair
See exchange key pair.
key exchange private key
The private key of an exchange key pair.

See also exchange key pair.

key exchange protocol
A protocol by which two parties exchange information to establish a shared secret. The shared secret is then typically used as a symmetric encryption key.
key exchange public key
The public key of an exchange key pair.

See also exchange key pair.

key generation functions
A set of functions used by applications to generate and customize cryptographic keys. These functions include full support for changing chaining modes, initialization vectors, and other encryption features.
key length
Values specified by some providers that indicate the length of the public/private key pairs and session keys used with that provider.
key pair
A private key and its related public key.


L

logical store
See virtual store.
low-level message functions
Message management functions that operate at a higher level than the base cryptographic functions. These functions provide functionality for encoding data for transmission and for decoding data that has been received.

Low-level message functions provide more flexibility than simplified message functions, but require more function calls.

See also simplified message functions.


M

MAC
The CryptoAPI algorithm name for the Message Authentication Code algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_MAC) and class (ALG_CLASS_HASH).

See also Message Authentication Code algorithm.

master key
The key used by the client and server for all session key generation. The master key is used to generate the client-read key, the client-write key, the server-read key, and the server-write key.

Master keys can be exported as simple key blobs.

MD2
The CryptoAPI algorithm name for the MD2 hash algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_MD2) and class (ALG_CLASS_HASH).

See also MD2 algorithm.

MD2 algorithm
(MD2) A hashing algorithm that creates a 128-bit hash value, which is twice the size of the block (64 bits).

The CryptoAPI references this algorithm by its type (CALG_MD2), name (MAC), and class (ALG_CLASS_HASH).

MD2 was developed by RSA Data Security, Inc. See also MD5 algorithm.

MD4
The CryptoAPI algorithm name for the MD4 hash algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_MD4) and class (ALG_CLASS_HASH).

See MD4 algorithm.

MD4 algorithm
(MD4) A hashing algorithm that creates a 128-bit hash value, which is twice the size of the block (64 bits).

MD4 was developed by RSA Data Security, Inc. See also MD5 algorithm.

MD5
The CryptoAPI algorithm name for the MD5 hash algorithm.

See MD5 algorithm.

MD5 algorithm
(MD5) A hashing algorithm that creates a 128-bit hash value, which is twice the size of the block (64 bits).

The CryptoAPI references this algorithm by its algorithm identifier (CALG_MD5), name (MD5), and class (ALG_CLASS_HASH).

MD5 was developed by RSA Data Security, Inc. and is specified by PRON_RSA_FULL, PROV_RSA_SIG, PROV_DSS, PROV_DSS_DH, and PROV_MS_EXCHANGE provider types.

message
Any data that has been encoded for transmission to or received from a person or entity. Messages may be encrypted for privacy, digitally signed for authentication purposes, or both.
Message Authentication Code algorithm
(MAC) A keyed hashing algorithm that uses a symmetric session key. When using this type of algorithm, the receiving application must also posses the session key to recompute the hash value so it can verify that the base data has not changed.

The CryptoAPI references this algorithm by its type (CALG_MAC), name (MAC) and class (ALG_CLASS_HASH).

message digest
See hash value.
message encoding type
Defines how the message is encoded. The message encoding type is stored in the high-order word of the encoding type structure.

Current defined encoding types are: CRYPT_ASN_ENCODING, X509_ASN_ENCODING, and PKCS_7_ASN_ENCODING.

message management functions
Functions that provide two levels of message management: low-level message functions and simplified message functions. The low-level message functions provide more flexibility than the simplified message functions; however, they require more function calls.
message signing functions
Functions used to sign messages and data.

See also simplified message functions.


N

National Institute of Standards and Technology
(NIST) A division of the United States Department of Commerce that publishes official standards for both government and private sector computer systems. These standards are published as Federal Information Processing Standards(FIPS) publications.

In 1987, NIST was directed to define standards for ensuring the security of sensitive but unclassified information in government computer systems.

NIST
See National Institute of Standards and Technology.
nonce
A randomly generated value used to defeat "replay" attacks.


O

OFB
See Output Feedback.
OID
Object identifier (ASN.1) for abstract objects specified by ASN.1.

The object identifier is a sequence of integers that identifies objects such as algorithms or attribute types.

outer content
The enhancements for some encapsulated data. This term is used primarily when discussing enhanced data (the inner content) in PKCS #7 messages.
Output Feedback
(OFB) A block cipher mode that uses feedback similar to the Cipher Feedback (CFB) mode. The only difference between the two modes is how the shift register is filled.

See also Cipher Feedback.


P

padding
A string, typically added when the last plaintext block is short. For example, if the block length is 64 bits and the last block contains only 40 bits, then 24 bits of padding must be added to the last block. The padding string may contain zeros, alternating zeros and ones, or some other pattern.

Applications using the CryptoAPI need not add padding to their plaintext before it is encrypted, nor do they have to remove it after decrypting. This is all handled automatically.

persistent storage
Any storage medium that remains intact when the power to it is disconnected. Many certificate store databases are forms of persistent storage.
PKCS
See Public-Key Cryptography Standards.
PKCS #7 STANDARD
A standard that defines a general syntax for encryption and authentication, as well as adding other message attributes, such as timestamps, to the message.
PKCS_7_ASN_ENCODING
Specifies message encoding. Message encoding types are stored in the high-order word of a DWORD (value is: 0x00010000).
plaintext
A message that is not encrypted. Plaintext messages are also referred to as cleartext messages.
PRF
See Pseudo-Random Function.
privacy
The condition of being isolated from view or secret. With respect to messages, private messages are encrypted messages whose text is hidden from view. With respect to keys, a private key is a secret key concealed from others.
private key
The secret half of a key pair used in a public key algorithm. Private keys are typically used to encrypt a symmetric session key, digitally sign a message, or decrypt a message that has been encrypted with the corresponding public key.

See also public key.

private key blob
A key blob that contains a complete public/private key pair. Private key blobs are used by administrative programs to transport key pairs. As the private key portion of the key pair is extremely confidential, these blobs are typically kept encrypted with a symmetric cipher.

These key blobs can also be used by advanced applications where the key pairs are stored within the application, rather than relying on the CSP's storage mechanism.

A key blob is created by calling CryptExportKey.

PROV_DH_SCHANNEL
See PROV_DH_SCHANNEL provider type.
PROV_DSS
See PROV_DSS provider type.
PROV_DSS Provider Type
Predefined provider type that only supports digital signatures and hashes. It specifies the DSA signature algorithm, and the MD5 and SHA-1 hashing algorithms.
PROV_DSS_DH
See PROV_DSS_DH provider type.
PROV_DSS_DH provider type
Predefined provider type that provides key exchange, digital signature, and hashing algorithms. It is similar to the PROV_DSS provider type.
PROV_FORTEZZA
See PROV_FORTEZZA provider type.
PROV_FORTEZZA provider type
Predefined provider type that provides key exchange, digital signature, encryption, and hashing algorithms. The cryptographic protocols and algorithms specified by this provider type are owned by the National Institute of Standards and Technology (NIST).
PROV_MS_EXCHANGE
See PROV_MS_EXCHANGE provider type.
PROV_MS_EXCHANGE provider type
Predefined provider type designed for the needs of Microsoft Exchange, as well as other applications that are compatible with Microsoft Mail. It provides key exchange, digital signature, encryption, and hashing algorithms.
PROV_RSA_FULL
See PROV_RSA_FULL provider type.
PROV_RSA_FULL provider type
Predefined provider type defined by Microsoft and RSA Data Security, Inc. This general purpose provider type provides key exchange, digital signature, encryption, and hashing algorithms.

The key exchange, digital signature, and encryption algorithms are based on RSA public-key cryptography.

PROV_RSA_SIG
See PROV_RSA_SIG provider type.
PROV_RSA_SIG provider type
Predefined provider type defined by Microsoft and RSA Data Security. This provider type is a subset of PROV_RSA_FULL that provides only digital signature and hashing algorithms.

The digital signature algorithm is an RSA public-key algorithm.

PROV_SSL
See PROV_SSL provider type.
PROV_SSL provider type
Predefined provider type that supports the Secure Sockets Layer (SSL) protocol. This type provides key encryption, digital signature, encryption, and hashing algorithms.

A specification explaining SSL is available from Netscape Communications Corp.

provider
See Cryptographic Service Provider.
provider name
A name used to identify a CSP. For example, the Microsoft Base Cryptographic Provider version 1.0.

The provider name is typically used when calling CryptAquireContext to connect to a CSP.

provider type
A term used to identify a type of CSP. CSPs are grouped into different provider types that represent a specific families of standard data formats and protocols. In contrast to a CSP's unique provider name, provider types are not unique for a given CSP.

The provider type is typically used when calling CryptAquireContext to connect to a CSP.

Pseudo-Random Function
(PRF) A function that takes a key, label, and seed as input, then produces an output of arbitrary length.
public/private key pair
A set of cryptographic keys used for public-key cryptography. For each user, a CSP usually maintains two public/private key pairs: an exchange key pair and a digital signature key pair. Both key pairs are maintained from session to session.

See exchange key pair and signature key pair.

public key
A cryptographic key typically used when decrypting a session key or a digital signature.

The public key can also be used to encrypt a message, guaranteeing that only the person with the corresponding private key can decrypt the message.

See also private key.

public-key algorithm
An asymmetric cipher that uses two keys, one for encryption, the public key, and the other for decryption, the private key.

As implied by the key names, the public key used to encode plaintext can be made available to anyone. However, the private key must remain secret. Only the private key can decrypt the ciphertext.

The public-key algorithm used in this process is slow (on the order of 1,000 times slower than symmetric algorithms), and is typically used to encrypt session keys or digitally sign a message.

See also public key and private key.

public-key blob
A blob used to store the public key portion of a public/private key pair. Public key blobs are not encrypted as the public key contained within is not secret

A public-key blob is created by calling CryptExportKey.

Public-Key Cryptography Standards
(PKCS) A set of syntax standards covering a number of security functions, including methods for signing data, exchanging keys, requesting certificates, public-key encryption and decryption, and many more security functions.
public-key encryption
Encryption that uses a pair of keys, one key to encrypt data and the other key to decrypt data. In contrast, symmetric encryption algorithms that use the same key for both encryption and decryption.

In practice, public-key cryptography is typically used to protect the session key used by a symmetric encryption algorithm. In this case, the public key is used to encrypt the session key, which in turn was used to encrypt some data, and the private key is used for decryption.

In addition to protecting session keys, public-key cryptography may also be used to digitally sign a message (using the private key) and validate the signature (using the public key).

See also public-key algorithm.


R

RC2
The CryptoAPI algorithm name for the RC2 algorithm.

See also RC2 block algorithm.

RC2 block algorithm
A data encryption algorithm based on the RC2 64-bit symmetric block cipher. RC2 is specified by PROV_RSA_FULL provider types.

The CryptoAPI references this algorithm by its identifier (CALG_RC2), name (RC2), and class (ALG_CLASS_DATA_ENCRYPT).

RC4
The CryptoAPI algorithm name for the RC4 algorithm.

See also RC4 stream algorithm.

RC4 stream algorithm
A data encryption algorithm based on the RC4 symmetric stream cipher. RC4 is specified by PROV_RSA_FULL provider types.

The CryptoAPI references this algorithm by its identifier (CALG_RC4), name (RC4), and class (ALG_CLASS_DATA_ENCRYPT).

RDN
See relative distinguished name.
relative distinguished name
(RDN) An entity included as the Subject in a request for a certificate. The elements in an RDN are defined by its attributes and do not need to include a name.

With respect to the CryptoAPI, an RDN is defined by a CERT_RDN structure, which in turn points to an array of CERT_RDN_ATTR attribute structures. Each attribute structure specifies a single attribute.

relocated store
A certificate store that has been moved from its default registry location to a different location in the registry.
remote store
A certificate store located on another computer, such as a file server or some other shared remote computer.
revocation list
See Certificate Revocation List.
RPC
Remote Procedure Calls. Microsoft RPC provides a programming model, standards, and tools for building distributed applications.

For information on RPC, see the RPC Programmer's Guide under Networking and Distributed Services section of the Platform SDK.

RSA
See RSA Public-Key algorithm.
RSA_KEYX
The CryptoAPI algorithm name for the RSA key exchange algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_RSA_KEYX) and class (ALG_CLASS_KEY_EXCHANGE).
RSA_SIGN
The CryptoAPI algorithm name for the RSA signature algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_RSA_SIGN) and class (ALG_CLASS_SIGNATURE).
RSA Public-Key algorithm
A key exchange and signature algorithm based on the popular RSA Public-Key cipher. This algorithm is used by PROV_RSA_FULL, PROV_RSA_SIG, PROV_MS_EXCHANGE, and PROV_SSL provider types.

The CryptoAPI references this algorithm by its identifiers (CALG_RSA_KEYX and CALG_RSA_SIGN), names (RSA_KEYX and RSA_SIGN) and class (ALG_CLASS_KEY_EXCHANGE).


S

salt value
Random data that is sometimes include as part of a session key. When added to a session key, the plaintext salt data is placed in front of the encrypted key data.

Salt values are added to increase the work required to mount a brute-force (dictionary) attack against data encrypted with a symmetric-key cipher.

Salt values are generated by calling CryptGenRandom.

SChannel
A security package that provides authentication between clients and servers.
Secure Hash Algorithm
(SHA-1) A hashing algorithm that generates a 160-bit hash value. SHA-1 is used with the Digital Signature Algorithm(DSA) in the Digital Signature Standard(DSS), among other places.

The CryptoAPI references this algorithm by its identifier (CALG_SHA), name (SHA), and class (ALG_CLASS_HASH).

SHA-1 was developed by the National Institute of Standards and Technology (NIST) and by the National Security Agency (NSA).

Secure Hash Standard
A standard designed by NIST and NSA. This standard defines the Secure Hash Algorithm (SHA-1) for use with the Digital Signature Standard (DSS).

See also Secure Hash Algorithm.

Secure Sockets Layer protocol
(SSL) A protocol for secure network communications using a combination of public and private key technology.
Secure/Multipurpose Internet Mail Extensions
(S/MIME) An e-mail security standard that makes use of public key encryption.
serialize
The process of converting data into a string of ones and zeros so that it can be transmitted serially. Encoding is part of this process.
server
A computer that responds to commands from a client computer. The client and server work together to perform distributive application functionality.

See also client.

session
An exchange of messages under the protection of a single piece of keying material. For example, SSL sessions use a single key to send multiple messages back and forth under that key.
session key
A key used primarily for data encryption and decryption. Session keys are typically used with symmetric encryption algorithms where the same key is used for both encryption and decryption. For this reason, session and symmetric keys usually refer to the same type of key.

A session key consists of a random number of approximately 40 to 2000 bits. Session keys can be derived from hash values by calling CryptDeriveKey.

session-key derivation scheme
Specifies when a key is derived from a hash. Methods used depend on the CSP type.
SHA
The CryptoAPI name for the Secure Hash algorithm. The CryptoAPI also references this algorithm by its algorithm identifier (CALG_SHA) and class (ALG_CLASS_HASH).

See also Secure Hash Algorithm.

SHS
See Secure Hash Standard.
signature and data verification functions
Simplified message functions used to sign outgoing messages and verify the authenticity of applied signatures in received messages and related data.

See simplified message functions.

signature file
A file that contains the signature of a particular CSP. The signature file is necessary to ensure that the CryptoAPI recognizes the CSP. The CryptoAPI validates this signature periodically to make certain the CSP has not been tampered with.
signature functions
Functions used to create and verify digital signatures.

See also simplified message functions.

signature key pair
The public/private key pair used for authenticating (digitally signing) messages. Signature key pairs are created by calling CryptGenKey.

See also exchange key pair.

signature private key
The private key of a signature key pair.

See signature key pair.

signed and enveloped data
A data content type defined by PKCS #7. This data type consists of encrypted content of any type, encrypted content-encryption keys for one or more recipients, and doubly encrypted message hash(es) for one or more signers. The double encryption consists of an encryption with a signer's private key followed by an encryption with the content-encryption key.
signed data
A data content type defined by PKCS #7. This data type consists of any type of content plus encrypted message hashes (digests) of the content for zero or more signers. The resulting hash(es) can be used to confirm who signed the message. These hashes also confirm that the original message has not been modified since the message was signed.
simple key blob
A session key encrypted with the key-exchange public key of the destination user. This key blob type is used when storing a session key or transmitting a session key to another user. A key blob is created by calling CryptExportKey.
simplified message functions
Message management functions such as message encryption, decryption, signing and signature verification functions. Simplified message functions operate at a higher level than the base cryptographic functions or the low-level message functions.

Simplified message functions wrap several of the base cryptographic, low-level message, and certificate functions into a single function that performs a specific task in a specific manner, such as encrypting a PKCS #7 message or signing a message.

See also low-level message functions.

Skipjack
An encryption algorithm specified as part of the Fortezza encryption suite. Skipjack is a symmetric cipher with a fixed key length of 80 bits.

Skipjack is a classified algorithm created by the United States National Security Agency (NSA). The technical details of the Skipjack algorithm are secret.

S/MIME
See Secure/Multipurpose Internet Mail Extensions.
SSL
See Secure Sockets Layer protocol.
SSL3 Client Authentication algorithm
An algorithm used for client authentication in Secure Sockets Layer(SSL) version 3. In the SSL3 protocol, a concatenation of an MD5 hash and a SHA-1 hash is signed with an RSA private key. CryptoAPI and the Microsoft Base and Enhanced Cryptographic Providers support SSL3 with the hash type CALG_SSL3_SHAMD5.
SSL3 protocol
Version 3 of the Secure Sockets Layer (SSL) protocol.
stream cipher
A cipher that serially encrypts data, one bit at a time.

See also block cipher.

symmetric algorithm
A cryptographic algorithm that typically uses a single key, often referred to as a session key, for encryption and decryption. Symmetric algorithms can be divided into two categories, stream algorithms and block algorithms (also called stream and block ciphers).

See also stream cipher and block cipher.

symmetric encryption
Encryption that uses a single key for both encryption and decryption. Symmetric encryption is preferred when encrypting large amounts of data. Some of the more common symmetric encryption algorithms are RC2, RC4, and Data Encryption Standard (DES).

See also public-key encryption.

symmetric key
A single key, typically a session key, used for both encryption and decryption.

See also session key.


T

three-phase key-exchange protocol
A protocol used to generate an authenticated and encrypted connection between two users on a nonsecure network.

Users exchange a set of messages to negotiate a pair of encryption keys. One key is used by the sender to encrypt messages sent to the receiver and the other is used by the receiver to encrypt messages sent to the sender. This protocol ensures that both users are active and are sending messages directly to each other.

TLS
See Transport Layer Security protocol.
transport layer
The network layer that is responsible for both quality of service and accurate delivery of information. Among the tasks performed in this layer are error detection and correction.
Transport Layer Security protocol
(TLS) A protocol that provides communications privacy and security between two applications communicating over a network.
trust list
See certificate trust list.


U

UCS
See Universal Character Set.
Universal Character Set
(UCS) A 16-bit character set.


V

virtual store
A certificate store that consists of a collection of other certificate stores.

A single search or enumeration function on a virtual store will search all of the stores that are members of the virtual stores collection. Any addition to a virtual store will add an element to one of the members of that store.


X

X.200
An Open Systems Interconnect (OSI) standard.

See also Open Systems Interconnect.

X.208
The ITU standard defining ASN.1.
X.209
The ITU standard that defines BER encodings for ASN.1 objects.

See also Basic Encoding Rules.

X.400
The ITU standard that defines message tokens.
X.500
The ITU standard that defines the structure of a global dictionary.
X.509
The ITU standard that defines the structure of an X.509 public-key certificate. Also available as ISO/IEC 9594-8.
X.509 certificate
A standard certificate defined in the ITU-T recommendation X.509. An X.509 certificate includes information about the person or entity to whom the certificate is issued, information about the certificate, plus optional information about the CA issuing the certificate.

Subject information may include the entity's name, public key, public-key algorithm, and an optional unique subject ID.

X509_ASN_ENCODING
Specifies certificate encoding. Certificate encoding types are stored in the low-order word of a DWORD (value is: 0x00000001).

Functionally the same as CRYPT_ASN_ENCODING.

XOR
Exclusive OR. A Boolean operation that yields true only if one of its operands are true and the other is false. If both operands are the same (either True or False), the operation yields false.


Interoperability with RSA CSPs

The information that used to be contained in this directory can now be found in Microsoft Cryptographic Service Providers, and in Interoperability with RSA CSPs, which is located in the Cryptographic Service Providers section of the Platform SDK.


The Microsoft CryptoAPI Summary of Changes

The following sections show the changes that have occurred to the Microsoft® CryptoAPI during the time between the Microsoft Security Design Review (SDR) conference that was held in September of 1996 and the end of January 1997.

This summary of changes involves the wincrypt.h and crypt32.dll files.


Global Changes

  • Changed "Digest" to "Hash", "digest" to "hash" and "DIGEST" to "HASH".
  • Prefixed all data structures with one of the following to avoid name conflicts with other include files:

    CERT_, PCERT_, _CERT_,

    CRYPT_, PCRYPT_, _CRYPT_,

    CMSG_, PCMSG_, _CMSG_

  • The *_OBJID constants were renamed to szOID_* constants. For example,

    AUTHORITY_KEY_IDENTIFIER_OBJID renamed to szOID_AUTHORITY_KEY_IDENTIFIER.

  • In wincrypt.h, all data structures and APIs having to do with SET were removed.
  • In wincrypt.h, all data structures having to do with SPC were moved to signcde.h.
  • The certificate and message encoding types were consolidated into a single DWORD. For more information, see Certificate and Message Encoding Types.


Data Structure Changes

  • BLOB Structure (CRYPT_DATA_BLOB, ...)

    The order of the cbData and pbData fields were switched. cbData is now the first field in the data structure.

  • BIT_BLOB (CRYPT_BIT_BLOB)

    The order of the cbData and pbData fields were switched. cbData is now the first field in the data structure.

  • PUBLIC_KEY_INFO (CERT_PUBLIC_KEY_INFO)

    The PublicKey field was changed from containing the CSP Public Key Blob format to containing the still encoded representation.

  • CERT_INFO

    The SubjectPublicKeyAlgorithm and SubjectPublicKey fields were combined into the SubjectPublicKeyInfo field. The SubjectPublicKeyInfo contains the above CERT_PUBLIC_KEY_INFO.

  • CERT_REQUEST_INFO

    The SubjectPublicKeyAlgorithm and SubjectPublicKey fields were combined into the SubjectPublicKeyInfo field. The SubjectPublicKeyInfo contains the above CERT_PUBLIC_KEY_INFO.


Decode and Encode Object Changes

  • The DecodeObject and EncodeObject functions were renamed to CryptDecodeObject and CryptEncodeObject.
  • The dwFlags parameter was added to CryptDecodeObject.

    The CRYPT_DECODE_NOCOPY_FLAG can be set to enable the nocopy optimization. This optimization, where appropriate, updates the pvStructInfo fields to point to content residing within pbEncoded instead of making a copy of and appending to pvStructInfo. However, when this optimization is used, pbEncoded can't be freed until pvStructInfo is freed.

  • The data structures used by CryptEncodeObject and CryptDecodeObject were added and changed.

    At the time of the SDR, there were 13 predefined data structures that could be used with CryptEncodeObject and CryptDecodeObject. We have added eight more.

    The X509_SET_* data structures have been deleted. The X509_SPC_* data structures have been moved to the signcde.h file.

  • At the time of the SDR, there were individual encode and decode functions for the first 13 predefined data structures. These functions have been deleted.
  • For X509_CERT, the data structure used for encode/decode was changed from CERT_ENCODING to CERT_SIGNED_CONTENT_INFO. The CERT_ENCODING data structure has been deleted.

The following table maps the lpszStructTypes defined at the SDR to the corresponding current data structures:

SDR Structure | Current Structure
X509_CERT | CERT_SIGNED_CONTENT_INFO
X509_CERT_TO_BE_SIGNED | CERT_INFO
X509_CERT_CRL_TO_BE_SIGNED | CRL_INFO
X509_CERT_REQUEST_TO_BE_SIGNED | CERT_REQUEST_INFO
X509_EXTENSIONS | CERT_EXTENSIONS
X509_NAME_VALUE | CERT_NAME_VALUE
X509_NAME | CERT_NAME_INFO
X509_PUBLIC_KEY_INFO | CERT_PUBLIC_KEY_INFO
X509_AUTHORITY_KEY_ID | CERT_AUTHORITY_KEY_ID_INFO
X509_KEY_ATTRIBUTES | CERT_KEY_ATTRIBUTES_INFO
X509_KEY_USAGE_RESTRICTION | CERT_KEY_USAGE_RESTRICTION_INFO
X509_ALTERNATE_NAME | CERT_ALT_NAME_INFO
X509_BASIC_CONSTRAINTS | CERT_BASIC_CONSTRAINTS_INFO

The following lpszStructTypes have been added:

X509_KEY_USAGE | CRYPT_BIT_BLOB
X509_BASIC_CONSTRAINTS2 | CERT_BASIC_CONSTRAINTS2_INFO
X509_CERT_POLICIES | CERT_POLICIES_INFO
PKCS_UTC_TIME | FILETIME
PKCS_TIME_REQUEST | CRYPT_TIME_STAMP_REQUEST_INFO
RSA_CSP_PUBLICKEYBLOB | RSAPUBKEY
X509_UNICODE_NAME | CERT_NAME_INFO
PKCS7_SIGNER_INFO | CMSG_SIGNER_INFO


New Object Identifier (OID) Installable and Registerable Support Functions

The following OID installation and registration functions were added after the SDR:

CryptEnumOIDFunction

CryptFreeOIDFunctionAddress

CryptGetDefaultOIDDllList

CryptGetDefaultOIDFunctionAddress

CryptGetOIDFunctionAddress

CryptGetOIDFunctionValue

CryptInitOIDFunctionSet

CryptInstallOIDFunctionAddress

CryptRegisterDefaultOIDFunction

CryptRegisterOIDFunction

CryptSetOIDFunctionValue

CryptUnregisterDefaultOIDFunction

CryptUnregisterOIDFunction


Error Code Changes

The error codes were moved from wincrypt.h to winerror.h and were renamed or mapped to existing error codes as follows:

CRMSG_E_GENERAL to CRYPT_E_MSG_ERROR

CERT_BAD_PARAMETER to E_INVALIDARG

CERT_BAD_LENGTH to ERROR_MORE_DATA

CERT_BAD_ENCODE to CRYPT_E_BAD_ENCODE

CERT_OUT_OF_MEMORY to E_OUTOFMEMORY

CERT_MUST_COPY_ENCODED to E_INVALIDARG

CERT_OBJID_NOT_FOUND (not used)

CERT_OSS_ERROR to CRYPT_E_OSS_ERROR

CERT_STORE_BAD_PARAMETER to E_INVALIDARG

CERT_STORE_BAD_LEN to ERROR_MORE_DATA

CERT_STORE_BAD_FLAGS to E_INVALIDARG

CERT_STORE_BAD_FILE to CRYPT_E_FILE_ERROR

CERT_STORE_NO_SUCH_PROPERTY to CRYPT_E_NOT_FOUND

CERT_STORE_ALREADY_IN_STORE to CRYPT_E_EXISTS

CERT_STORE_NOT_IMPLEMENTED to E_NOTIMPL

CERT_STORE_NOT_FOUND to CRYPT_E_NOT_FOUND

CERT_STORE_NO_CRYPT_PROV to CRYPT_E_NO_PROVIDER

CERT_STORE_SELF_SIGNED to CRYPT_E_SELF_SIGNED

CERT_STORE_DELETED_PREV to CRYPT_E_DELETED_PREV

CERT_HELPER_NO_MATCH to CRYPT_E_NO_MATCH

SCA_BAD_LEN_PARAMETER to ERROR_MORE_DATA

SCA_BAD_PARAMETER to E_INVALIDARG

SCA_UNEXPECTED_MSG_TYPE to
CRYPT_E_UNEXPECTED_MSG_TYPE

SCA_NO_CERT_KEY_PROV to CRYPT_E_NO_KEY_PROPERTY

SCA_NO_XCHG_CERT to CRYPT_E_NO_DECRYPT_CERT

SCA_BAD_MSG to CRYPT_E_BAD_MSG


New Low-Level Cryptographic Message Functions and Data Structures

Most of the cryptographic message functions and data structures were included in the SDR version of wincrypt.h. However, no documentation was provided on their usage. Therefore, for the purpose of this Summary of Changes, assume that all the low-level cryptographic message functions were added after the SDR. All the functions start with the CryptMsg prefix. The data structures are prefixed with CMSG_, PCMSG_ or _CMSG_.

For an overview, see Using Low-Level Message Functions. For details, see Low Level Message Functions.


Deleted Certificate Store Function

The following undocumented certificate store function was deleted after the SDR:

CertCleanStore


Unchanged Certificate Store Functions

No changes were made to the following functions after the SDR:

CertCreateCertificateContext

CertCreateCRLContext

CertDeleteCertificateFromStore

CertDeleteCRLFromStore

CertDuplicateCertificateContext

CertDuplicateCRLContext

CertDuplicateStore

CertEnumCertificatesInStore

CertFreeCertificateContext

CertFreeCRLContext

CertGetCRLFromStore

CertGetIssuerCertificateFromStore

CertGetSubjectCertificateFromStore


Changes to Certificate Store Functions

This section contains a summary of changes made to the functions after the SDR:

  • CertAddCertificateContextToStore

    The dwAddDisposition and ppStoreContext parameters were added. For SDR compatibility, set them to CERT_STORE_ADD_USE_EXISTING and NULL respectively.

  • CertAddCertificateToStore

    Renamed to CertAddEncodedCertificateToStore. The dwAddDisposition parameter was added. For SDR compatibility, set this parameter to CERT_STORE_ADD_USE_EXISTING.

  • CertAddCRLContextToStore

    The dwAddDisposition and ppStoreContext parameters were added. For SDR compatibility, set them to CERT_STORE_ADD_USE_EXISTING and NULL respectively.

  • CertAddCRLToStore

    Renamed to CertAddEncodedCRLToStore. The dwAddDisposition parameter was added. For SDR compatibility, set this parameter to CERT_STORE_ADD_USE_EXISTING.

  • CertCloseStore

    The dwFlags parameter was added. You can set the CERT_CLOSE_STORE_FORCE_FLAG to force all contexts to be released and the store's memory to be freed.

    You can set the CERT_CLOSE_STORE_CHECK_FLAG to check that this is the last close store and all contexts have been released.

  • CertFindCertificateInStore

    The following find types were added to help find a certificate containing the specified subject/issuer name string:

    CERT_FIND_SUBJECT_STR_A

    CERT_FIND_SUBJECT_STR_W | CERT_FIND_SUBJECT_STR

    CERT_FIND_ISSUER_STR_A

    CERT_FIND_ISSUER_STR_W | CERT_FIND_ISSUER_STR

    The following type was added to help find a certificate having a CERT_KEY_SPEC_PROP_ID property matching the specified key spec:

    CERT_FIND_KEY_SPEC

  • CertGetCertificateContextProperty, CertGetCRLContextProperty, CertSetCertificateContextProperty, CertSetCRLContextProperty

    The following predefined properties were added for these functions: CERT_KEY_CONTEXT_PROP_ID and CERT_KEY_SPEC_PROP_ID. The range of user definable properties was changed from 8…31 to 0x8000…0xFFFF (CERT_FIRST_USER_PROP_ID … CERT_LAST_USER_PROP_ID).

  • CertOpenStore

    The first parameter identifies the provider type. It's type was changed from a DWORD to an LPCSTR, and more predefined provider types were added. Also, OID installable and registerable providers are now supported. See Reference Overview for a complete list of the predefined provider types, and for details about installable certificate store providers.

    The provider type constants defined in the SDR are still valid.

    The behavior of CertOpenStore when the hCryptProv parameter is zero was changed as follows:

    If hCryptProv is zero, then, the default provider and container for the PROV_RSA_FULL provider type is acquired via a call to CryptAcquireContext with the CRYPT_VERIFYCONTEXT flag set. However, the call to CryptAcquireContext is deferred until the first create hash or verify signature is required. In addition, once acquired, the default provider isn't released until the current process exits. The acquired default provider is shared across all stores and threads.

  • CertSaveStore

    The dwMsgAndCertEncodingType, dwSaveAs and dwSaveTo parameters were added. The SDR version only supported saving the serialized store to a file. Now it supports saving as either a serialized store or PKCS #7 message to a file or memory.

  • CertVerifySubjectCertificate

    Renamed to CertVerifySubjectCertificateContext.


New Certificate Store Functions

The following certificate store functions were added after the SDR:

CertAddSerializedElementToStore

CertEnumCertificateContextProperties

CertEnumCRLContextProperties

CertSerializeCertificateStoreElement

CertSerializeCRLStoreElement


Deleted Certificate Helper Functions

The following certificate helper functions were deleted after the SDR:

CertHelperVerifySignature - use CryptVerifyCertificateSignature

CertIsIssuerOfCRL - use CertCompareCertificateName

CertIsIssuerOfSubjectCertificate - use CertCompareCertificateName

CertGetPublicKey - use CryptExportPublicKeyInfo


Unchanged Certificate Helper Functions

No changes were made to the following functions after the SDR:

CertAlgIdToOID

CertCompareCertificate

CertCompareCertificateName

CertFindAttribute

CertFindExtension

CertFindRDNAttr

CertGetIntendedKeyUsage

CertOIDToAlgId

CertVerifyCRLTimeValidity

CertVerifyTimeValidity

CertVerifyValidityNesting


Changes to Certificate Helper Functions

The following changes were made to the functions after the SDR:

  • CertComparePublicKeys

    Renamed to CertComparePublicKeyInfo.

    The type of the pPublicKey parameter was changed from PCRYPT_BIT_BLOB to PCERT_PUBLIC_KEY_INFO.

  • CertHelperCreatePublicKeyInfo

    Renamed to CryptExportPublicKeyInfo. The dwCertEncodingType parameter was added.

  • CertHelperDigestPublicKeyInfo

    Renamed to CryptHashPublicKeyInfo. The dwFlags parameter was added.

  • CertHelperDigestToBeSigned

    Renamed to CryptHashToBeSigned.

  • CertIsRDNAttsInCertificateName

    Renamed to CertIsRDNAttrsInCertificateName. (SDR version was missing the letter 'r' in Attrs).

  • CertRDNValueToStr

    The returned count was changed to include the terminating zero character.

  • CryptDigestCertificate

    Renamed to CryptHashCertificate. The dwFlags parameter was added.

  • CryptSignCertificateContext

    Renamed to CryptSignCertificate.

    The pvHashAuxInfo parameter was added. pvHashAuxInfo currently isn't used, and must be set to NULL. The order of the dwKeySpec and dwCertEncodingType parameters were switched.

  • CryptVerifyCertificateSignature

    The type of the pPublicKey parameter was changed from PCRYPT_BIT_BLOB to PCERT_PUBLIC_KEY_INFO.

  • CryptVerifyRevocation

    Renamed to CertVerifyCRLRevocation. Don't confuse this with the newly added CertVerifyRevocation.


New Certificate Helper Functions

The following certificate helper functions were added after the SDR:

CertCompareIntegerBlob

CertNameToStr

CertVerifyRevocation

CryptExportPublicKeyInfoEx

CryptImportPublicKeyInfo

CryptImportPublicKeyInfoEx

CryptSignAndEncodeCertificate


Simplified Cryptographic Message Data Structure Changes

  • PFN_SCA_VERIFY_SIGNER_POLICY was renamed to PFN_CRYPT_GET_SIGNER_CERTIFICATE.
  • The SCA data structures were renamed:

    _SCA_*_PARA to _CRYPT_*_MESSAGE_PARA

    SCA_*_PARA to CRYPT_*_MESSAGE_PARA

    PSCA_*_PARA to PCRYPT_*_MESSAGE_PARA

    where * is: SIGN, VERIFY, ENCRYPT, DECRYPT or DIGEST (HASH).

    The dwVersion field in each of the above structures was replaced with the cbSize field. The cbSize field must be set to the size of the datastructure by using the sizeof( ) function.

  • SCA_DECRYPT_PARA (CRYPT_DECRYPT_MESSAGE_PARA)

    The dwMsgEncodingType and dwCertEncodingType fields were combined into single dwMsgAndCertEncodingType field.

  • SCA_DIGEST_PARA (CRYPT_HASH_MESSAGE_PARA)

    The pvHashAuxInfo field was added.

  • SCA_ENCRYPT_PARA (CRYPT_ENCRYPT_MESSAGE_PARA)

    The pvEncryptionAuxInfo, dwFlags and dwInnerContentType fields were added.

  • SCA_SIGN_PARA (CRYPT_SIGN_MESSAGE_PARA)

    Changed to support a single signer. The cSigningCert field was deleted. The rgpSigningCert field was renamed to pSigningCert. The pvHashAuxInfo, cAuthAttr, rgAuthAttr, cUnauthAttr, rgUnauthAttr, dwFlags, and dwInnerContentType fields were added.

  • SCA_VERIFY_PARA (CRYPT_VERIFY_MESSAGE_PARA)

    Renamed pfnVerifySignerPolicy to pfnGetSignerCertificate. Renamed pvVerifyArg to pvGetArg. Combined the dwMsgEncodingType and dwCertEncodingType fields into a single dwMsgAndCertEncodingType field.


Deleted Simplified Cryptographic Message Functions

The following undocumented simplified message functions using SET ExEncryption with PAN data were deleted:

CryptExDecryptAndVerifyMessage

CryptExDecryptMessage

CryptExEncryptMessage

CryptSignAndExEncryptMessage


Unchanged Simplified Cryptographic Message Functions

No changes were made to the following functions after the SDR:

CryptDecryptAndVerifyMessageSignature

CryptDecryptMessage

CryptEncryptMessage

CryptSignAndEncryptMessage

CryptSignMessage

CryptVerifyDetachedMessageSignature

CryptVerifyMessageSignature


Renamed Simplified Cryptographic Message Functions

The following simplified digest message functions were renamed:

CryptDigestMessage to CryptHashMessage

CryptVerifyDetachedMessageDigest to
CryptVerifyDetachedMessageHash

CryptVerifyMessageDigest to CryptVerifyMessageHash


New Simplified Cryptographic Message Functions

The following simplified message APIs were added:

CryptDecodeMessage

CryptGetMessageCertificates

CryptGetMessageSignerCount


Microsoft Cryptographic Providers--Release Notes

Microsoft Cryptographic Providers—Release Notes

There are now two cryptographic service providers (CSP) available from Microsoft®. The Microsoft Base Cryptographic Provider was the initial provider, and is distributed with Microsoft CryptoAPI versions 1.0 and 2.0. Now there is the Microsoft Enhanced Cryptographic Provider that can be used with either version as well. Both Providers now incorporate additional functionality in some of the functions. Additionally, the Enhanced Cryptographic Provider provides for stronger security through longer keys and additional algorithms

Note The Microsoft Enhanced Cryptographic Provider is currently available only within North America.

This document provides details on the following topics:

  • Key length comparison for the Enhanced and Base Cryptographic Providers.
  • Additional functionality when using salt values for 40-bit symmetric keys. The API functions affected are CryptGenKey, CryptDeriveKey, and CryptImportKey.
  • New functionality provided in the CryptSetKeyParam, CryptGetKeyParam, and CryptGetProvParam functions.
  • Security recommendations for signature operations.


Key Length Comparison

When used, the Microsoft Enhanced Cryptographic Provider (Enhanced Provider) provides an application with stronger security than currently available with the Microsoft Base Cryptographic Provider (Base Provider). This provides users with a greater degree of protection in keeping their sensitive data secure.

The following table lists the default key lengths supported by the Base Provider and the Enhanced Provider for the shown algorithms.

Algorithm | Base Provider | Enhanced Provider
RSA Key Exchange | 512-bit | 1,024-bit
RSA Signature | 512-bit | 1,024-bit
RC2 | 40-bit | 128-bit
RC4 | 40-bit | 128-bit
DES | Not supported | 56-bit
Triple DES (2-key) | Not supported | 112-bit
Triple DES (3-key) | Not supported | 168-bit

The DES and Triple DES algorithms are now supported in the Enhanced Provider.

The Enhanced Provider is backward-compatible with the Base Provider distributed with CryptoAPI versions 1.0 and 2.0, with the following exception: For session keys, both CSPs are limited to generating and deriving keys of default key length (40 bit for the Base Provider, and 128 bit for the Enhanced Provider), precluding the Enhanced Provider from creating keys with Base Provider–compatible key lengths. However, the Enhanced Provider can import key lengths of any size, up to 128 bits.

For more information on cryptographic service providers, see Interfacing with a Cryptographic Service Provider (CSP).


New Salt Value Functionality

The original Base Provider was designed such that every 40-bit symmetric key created has 11 bytes of zero-value salt (nonzero if CRYPT_CREATE_SALT is specified). This can be a problem, because a 40-bit symmetric key with a zero-value salt is not equivalent to a 40-bit symmetric key without salt. For interoperability, it may be necessary to specify that a key without salt be used.

It should be noted that this problem results from a default condition that occurs only with keys of exactly 40 bits. Any other key length does not have salt allocated by default.


No Salt Value

Both Providers can now use the CRYPT_NO_SALT flag, where a user can specify that no salt value gets allocated for a 40-bit symmetric key. The functions that accept this flag are CryptGenKey, CryptDeriveKey, and CryptImportKey. The default for these functions for the 40-bit symmetric key case provides backward compatibility by continuing the use of the 11-byte-long zero-value salt.

The example below shows the importation of a key without a salt value:

// Example showing key importation without a salt value.
//  [...] Assume an acquired context.

    // Import a key without salt.
    if (!CryptImportKey(
                hDefProv,
                pbKey,
                cbKey,
                NULL,
                CRYPT_NO_SALT,
                &hKey))
        goto Ret;

    // [...] Use key.

//  [...] Assume a destroyed key.
//  [...] Assume a released context.


Specifying a Salt Value

Functionality has been added to both providers so that a user can specify the value and length of the salt value to be used. With the Base Provider, the user can set a salt value by using the KP_SALT parameter value, but it is always assumed that 11 bytes are being set. To set a salt value with the Enhanced Provider, a user can call the CryptSetKeyParam function with the KP_SALT_EX parameter value specified and with the pbData parameter pointing to a CRYPTOAPI_BLOB structure containing the salt:

typedef struct _CRYPTOAPI_BLOB {
    DWORD            cbData;
    BYTE*            pbData;
} CRYPT_DATA_BLOB,  *PCRYPT_DATA_BLOB;

Note When using the Enhanced Provider, the total length of a symmetric key and its salt value cannot be greater than 128 bits .

KP_SALT continues to be provided for backward compatibility with the Base Provider. Newer applications should use the KP_SALT_EX parameter value.

The example below shows the importation of a key and setting of a salt value.

// Example showing key importation with a salt value.
//  [...] Assume an acquired context.

    // Specify 4 bytes of salt.
    BYTE rgbSalt[] = {0x01, 0x02, 0x03, 0x04};
    CRYPT_DATA_BLOB sSaltData;
    sSaltData.pbData = rgbSalt;
    sSaltData.cbData = sizeof(rgbSalt);

// Import a key.
if (!CryptImportKey(
                hDefProv,
                pbKey,
                cbKey,
                NULL,
                0,
                &hKey))
        goto Ret;

    // Set the 4 bytes of salt required.
    if (!CryptSetKeyParam(
                hKey,
                KP_SALT_EX,
                (BYTE*)&sSaltData,
                0))
        goto Ret;

    // [...] Use key.

//  [...] Assume a destroyed key.
//  [...] Assume a released context.


New Key-Length Functionality

In the original Base Provider, 40-bit symmetric keys were used exclusively. The addition of longer keys in the Enhanced Provider, and the fact that imported keys can be of arbitrary length, precipitates the need for a method of querying the length for a specific key. The following parameter value is provided for both providers to determine a key's length.

To get the actual length of a key in bits, a user can call CryptGetKeyParam with the KP_KEYLEN parameter value. The length of the key is located in the DWORD pointed to by pbData.

Note that it is desirable for applications to use the KP_KEYLEN parameter value to check for insufficient key lengths and notify the user when one is encountered. This protects against stepping-down attacks.

The following example shows how to query the length of a key.

// Example using CryptGetKeyParam with the KP_KEYLEN parameter value.

//  [...] Assume an acquired context.

    DWORD dwKeyLength;
    DWORD dwLen=sizeof(DWORD);

    // Generate a key.
    if (!CryptGenKey(
                hDefProv,
                CALG_RC2,
                0,
                &hKey))
        goto Ret;

    // Query the key length.
    if (!CryptGetKeyParam(
                hKey,
                KP_KEYLEN,
                (BYTE*)&dwKeyLength,
                &dwLen,
                0))
        goto Ret;

    if (!CryptDestroyKey(hKey))
        goto Ret;

    printf("The RC2 key generated is %d bits long\n", dwKeyLength);

//  [...] Assume a released context.


SHA Functionality

The following information relates to the original Base Provider. When enumerating algorithms by using a call to CryptGetProvParam (with parameter PP_ENUMALGS specified), the function reported, incorrectly, that the SHA hash algorithm was being used. This has been fixed in the Base Provider and now both providers correctly report SHA-1.

The flag CALG_SHA1 has been added to Wincrypt.h with the same value as CALG_SHA.


Security Recommendations for Signature Operations

Microsoft recommends against using the sDescription parameter in the CryptSignHash function. The lack of definition between the hashed data and the description string allows an arbitrary number of bits to flow undetected between the two. The description of the sDescription parameter from the CryptoAPI 2.0 Programmers Guide is included below:

sDescription
This description string is added to the hash object before the signature is generated. Whenever the signature is authenticated (with CryptVerifySignature), the exact same description string must be supplied. This ensures that both the signer and the authenticator agree on what is being signed or authenticated.

Some CSPs (not the Base Provider) may display this description string to the user. This lets the user confirm what he or she is signing. This protects the user from unscrupulous applications and also reduces misunderstandings.

Applications that continue to use the sDescription parameter should be careful, because no boundary exists between the hashed data and the description string.


Extending CryptoAPI Functionality

It is difficult to predict the future of cryptography and secure communications. New certificate types may emerge, various certificate extensions may find common usage, new message types may be introduced, and so on. Because of this, provisions have been made to extend the functionality of several key Microsoft® CryptoAPI functions.


OID Overview

This extensibility is achieved through the use of object identifiers (OID), encoding types, and associated DLLs. In the CryptoAPI, an OID can take any of the following forms:

  • A numeric string (for example, "1.2.3.500.88")
  • An alpha-numeric string (for example, "MyFunction")
  • A defined constant, where the value is less than or equal to 0xFFFF (for example, #define MY_FUNCTION (LPCSTR)10)

The functions that can have their functionality extended (those that can accept OID and encoding type arguments), search the system registry in an attempt to find a DLL associated with the OID that was passed to the function. If found, the function loads the DLL and calls the function. The following illustration shows this flow for the CryptEncodeObject function:

This extensibility allows Microsoft, and others, to extend the functionality of the CryptoAPI as the need arises. However, if this methodology is used, a burden is placed on the developer to write all the necessary code to complete the new functionality. For example, if you wanted to encode some new data structure, the new function would have to perform the entire encoding process from beginning to end. This is not a trivial task.


Creating the New Functionality

Currently, the following functions can be extended:

CryptoAPI Function | OID Function Name Define | OID Function Name String
CryptEncodeObject | CRYPT_OID_ENCODE_ OBJECT_FUNC | "CryptDllEncodeObject"
CryptDecodeObject | CRYPT_OID_DECODE_ OBJECT_FUNC | "CryptDllEncodeObject"
CertOpenStore | CRYPT_OID_OPEN_ STORE_PROV_FUNC | "CertDllOpenStoreProv"
CertVerifyCTLUsage | CRYPT_OID_VERIFY_ CTL_USAGE_FUNC | "CertDllVerifyCTLUsage"
CertVerifyRevocation | CRYPT_OID_VERIFY_ REVOCATION_FUNC | "CertDllVerifyRevocation"

To extend the functionality of one of these CryptoAPI functions, a new function, containing the new functionality, must be created in a DLL and be registered in the registry or installed in memory.

As shown in the previous illustration, when one of the listed functions gets called with the newly designated OID and encoding type, the new function gets called rather than calling one of the functions provided as part of the CryptoAPI.

The name of the newly developed function can be either that listed under "OID Function Name String" in the previous table, or a different name can be used at the time the function is registered. In either case, however, the new function's prototype must match that of the listed function. In all the cases except for CertOpenStore, this prototype is the same as the CryptoAPI calling function. In the case of CertOpenStore, the prototype is as follows:

BOOL WINAPI CertDllOpenStoreProv(
  IN LPCSTR lpszStoreProvider,
  IN DWORD dwMsgAndCertEncodingType,
  IN HCRYPTPROV hCryptProv,
  IN DWORD dwFlags,
  IN const void *pvPara,
  IN HCERTSTORE hCertStore,
  IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
);

Be aware that if the prototypes do not match, the system stack will get corrupted.

In addition to providing the new function in a DLL, when extending the functionality of CryptEncodeObject or CryptDecodeObject, a type definition for the new C data structure must be placed in a header file that gets included when the user's program is compiled.


Registering the New Functionality

Support for registering the new functionality in a system registry must be provided in the new DLL along with the new function. CryptoAPI functions are provided for assisting with this registration. (See OID Support Functions for details). The methodology used for registering the new functions is the use of Regsvr32.exe. This utility is provided with both Microsoft Windows NT® and Microsoft Windows® 95.

The new DLL must provide DllRegisterServer and DllUnregisterServer entry points for use by Regsvr32.exe. The CryptoAPI functions can be used within these entry points, as shown in the example code fragments that follow:

The DllRegisterServer Entry Point

STDAPI DllRegisterServer(void)
{
        if(!CryptRegisterOIDFunction(
            X509_ASN_ENCODING,                  // Encoding type
            CRYPT_OID_ENCODE_OBJECT_FUNC,       // Function name
            szOID_NEW_CERTIFICATE_TYPE,         // OID
            L"NewCert.dll",                     // Dll name
            L"NewCertificateTypeEncodeObject")) // Override function
                                                //   name
                        return E_FAIL;
        return S_OK;
}

The DllUnregisterServer Entry Point

STDAPI DllUnregisterServer(void)
{
        HRESULT     hr = S_OK;

        if(!CryptUnregisterOIDFunction(
                X509_ASN_ENCODING,             // Encoding type
                CRYPT_OID_ENCODE_OBJECT_FUNC,  // Function name
                szOID_NEW_CERTIFICATE_TYPE))   // OID
        {
                if(ERROR_FILE_NOT_FOUND != GetLastError())
                        hr = E_FAIL;
        }
        return hr;
}

This code must be compiled and linked into the new DLL, and these entry points, along with the function entry points, must be exported.

Users that need to install the new functionality on their computers, must run Regsvr32.exe from a command prompt window, specifying the name and path of the new DLL. Regsvr32.exe accesses CryptRegisterOIDFunction via the DllRegisterServer entry point, causing the new function and DLL to get registered in the registry.


Installing the New Functionality

To improve performance, it is possible to install the new functionality into memory. The CryptoAPI function searches memory for the functionality before searching the registry for the DLL. For this to work, the DLL must have been loaded previously.

The CryptoAPI CryptInstallOIDFunctionAddress function is used to install the address of the new functionality. It should be placed in the DllMain function of the DLL, as shown in the following example code fragment:

#define NEW_CERT_TYPE_ENCODE_COUNT
             (sizeof(NewCertificateTypeEncodeObject)/
                sizeof(NewCertificateTypeEncodeObject[0]))
BOOL
WINAPI
DllMain(
        HMODULE hModule,
        ULONG  ulReason,
        LPVOID lpReserved)
{
  static const CRYPT_OID_FUNC_ENTRY NewCertificateTypeEncodeObject[] =
    {
        szOID_NEW_CERTIFICATE_TYPE, NewCertificateTypeEncodeObject
    };

    switch (ulReason)
    {
        case DLL_PROCESS_ATTACH:
            if (!CryptInstallOIDFunctionAddress(
                  hModule,                      // Module handle
                  X509_ASN_ENCODING,            // Encoding type
                  CRYPT_OID_ENCODE_OBJECT_FUNC, // Function name
                  NEW_CERT_TYPE_ENCODE_COUNT,   // Number of
                                                //   array elements.
                  NewCertificateTypeEncodeObject, // Functions array
                  0))                             // dwFlags
            {
                printf("Install OID function address failed");
                return FALSE;
            }
            break;
        default:
            break;
    }
    return TRUE;
}

As stated earlier, to install new functionality into memory, the DLL must have been loaded. To facilitate this, it is good programming practice to always provide the code for both registering and installing the new functionality. This way, the first call to the function causes the DLL to get loaded (via the registry), and any subsequent calls will be found in memory, thereby improving performance.

If hModule is passed to CryptInstallOIDFunctionAddress, once installed, the DLL is not unloaded until the Crypt32.dll is unloaded.


Extending CertOpenStore Functionality

The certificate store is central to all certificate management operations. The functionality of the CertOpenStore function can be extended through the use of an installable (or registered) certificate-store-provider function. For an overview of how to install or register functions for use with the CryptoAPI see OID Overview.

CertOpenStore opens an empty store in memory and calls the store provider function (if it is registered or installed) by using the OID that was passed in the lpszStoreProvider parameter. For a list of the predefined provider types that are supplied with the CryptoAPI, see CertOpenStore.

The store provider function copies its certificates and CRLs to the "in-memory" store specified by the hCertStore handle passed to it. The new store provider function can use any of the CryptoAPI certificate store functions, such as, CertAddCertificateToStore or CertAddSerializedElementToStore, to add its certificates and CRLs to the "in-memory" store. In addition, the store-provider function optionally returns values for all of the data members of the CERT_STORE_PROV_INFO structure. The function only needs to update this structure if it supports additional callback functions. For example, if the store was to be a read-only store, the support of other callback functions probably would not be needed. For details and prototypes of the possible callback functions, see Certificate Store Provider Data Structure and Callback Functions.

One of the data members of the CERT_STORE_PROV_INFO structure is the rgpvStoreProvFunc array. If the store provider function needs to support one or more of the callback functions, it must provide pointers for this array. These pointers must point to the callback functions that are to be used for other certificate-store activities (such as closing the store). The following illustration shows the flow of this process.

As shown in the following illustration, after the store has been opened, other CryptoAPI functions (such as CertCloseStore) use the array of pointers to access the callback functions that perform the intended task. The definition of the CERT_STORE_PROV_INFO structure and the prototypes of the default callback functions that are supplied with the CryptoAPI are shown in Certificate Store Provider Data Structure and Callback Functions.


Certificate Store Provider Data Structure and Callback Functions

The data structure and callback functions defined in this section are used to register or install application-defined certificate store providers and to provide related functionality via callback functions. The data structure and functions can be found in Wincrypt.h.


CERT_STORE_PROV_INFO

CERT_STORE_PROV_INFO structures contain information returned by the installed CertDllOpenStoreProv when a store is opened with CertOpenStore.

When opening a store, CertOpenStore zeroes all fields in the CERT_STORE_PROV_INFO except cbSize, which is set to the size of CERT_STORE_PROV_INFO. The structure is updated by the CertDllOpenStoreProv installable function. If there are no additional callback functions to be called, then cStoreProvFunc remains zero upon return.

typedef struct _CERT_STORE_PROV_INFO {
    DWORD               cbSize;
    DWORD               cStoreProvFunc;
    void**              rgpvStoreProvFunc;
    HCERTSTOREPROV      hStoreProv;
    DWORD               dwStoreProvFlags;
    HCRYPTOIDFUNCADDR   HStoreProvFuncAddr2;
} CERT_STORE_PROV_INFO, *PCERT_STORE_PROV_INFO;

Members

cbSize
Set by CertOpenStore to the size of this structure.
cStoreProvFunc
The count of callback functions that are implemented, including any NULL values that are used in indexes prior to the last callback function implemented. For example, if only one callback function is implemented, but it is at index [2] (CERT_STORE_PROV_WRITE_CERT_FUNC), with NULL for indexes [0] and [1], then the number 3 should be passed for this parameter.
rgpvStoreProvFunc
An array of pointers to the callback functions. This array is indexed by the values given in the following table, and they must be in the order shown. The associated callback function is shown as well. When the count of callback functions (cStoreProvFunc) is greater than 1, the elements of rgpvStoreProvFunc that aren't supported with a callback function should be NULL. Otherwise they should contain the address of the callback function.
Index | Associated callback function
CERT_STORE_PROV_CLOSE_FUNC(0) | CertStoreProvCloseCallback
CERT_STORE_PROV_READ_CERT_FUNC(1) | CertStoreProvReadCertCallback
CERT_STORE_PROV_WRITE_CERT_FUNC(2) | CertStoreProvWriteCertCallback
CERT_STORE_PROV_DELETE_CERT_FUNC(3) | CertStoreProvDeleteCertCallback
CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC(4) | CertStoreProvSetCertPropertyCallback
CERT_STORE_PROV_READ_CRL_FUNC(5) | CertStoreProvReadCRLCallback
CERT_STORE_PROV_WRITE_CRL_FUNC(6) | CertStoreProvWriteCRLCallback
CERT_STORE_PROV_DELETE_CRL_FUNC(7) | CertStoreProvDeleteCRLCallback
CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC(8) | CertStoreProvSetCRLPropertyCallback
CERT_STORE_PROV_READ_CTL_FUNC(9) | CertStoreProvReadCTLCallback
CERT_STORE_PROV_WRITE_CTL_FUNC(10) | CertStoreProvWriteCTLCallback
CERT_STORE_PROV_DELETE_CTL_FUNC(11) | CertStoreProvDeleteCTLCallback
CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC(12) | CertStoreProvSetCTLPropertyCallback
CERT_STORE_PROV_CONTROL_FUNC(13) | CertStoreProvControlCallback
CERT_STORE_PROV_FIND_CERT_FUNC(14) | CertStoreProvFindCertCallback
CERT_STORE_PROV_FREE_FIND_CERT_FUNC(15) | CertStoreProvFreeFindCertCallback
CERT_STORE_PROV_GET_CERT_PROPERTY_FUNC(16) | CertStoreProvGetCertPropertyCallback
CERT_STORE_PROV_FIND_CRL_FUNC(17) | CertStoreProvFindCRLCallback
CERT_STORE_PROV_FREE_FIND_CRL_FUNC(18) | CertStoreProvFreeFindCRLCallback
CERT_STORE_PROV_GET_CRL_PROPERTY_FUNC(19) | CertStoreProvGetCRLPropertyCallback
CERT_STORE_PROV_FIND_CTL_FUNC(20) | CertStoreProvFindCTLCallback
CERT_STORE_PROV_FREE_FIND_CTL_FUNC(21) | CertStoreProvFreeFindCTLCallback
CERT_STORE_PROV_GET_CTL_PROPERTY_FUNC(22) | CertStoreProvGetCTLPropertyCallback

hStoreProv
This is the first parameter passed to all callbacks. Because this is a void pointer (HCERTSTOREPROV is type-defined to a void*), an application can specify the contents as desired. Typically, this may be a pointer to anything that is specific to an application's data structure, such as provider state information for each store opened.
dwStoreProvFlags
dwStoreProvFlags is set to CERT_STORE_PROV_EXTERNAL_FLAG to indicate that certificates, CRLs, and CTLs are external to the store's cache. It is set to CERT_STORE_PROV_DELETED_FLAG if the store was successfully deleted. Otherwise it is set to 0.


CertDllOpenStoreProv

An OID registerable or installable store-provider function that is called by CertOpenStore. It defines the store provider open function.

BOOL WINAPI CertDllOpenStoreProv(
  IN LPCSTR lpszStoreProvider,
  IN DWORD dwMsgAndCertEncodingType,
  IN HCRYPTPROV hCryptProv,
  IN DWORD dwFlags,
  IN const void *pvPara,
  IN HCERTSTORE hCertStore,
  IN OUT PCERT_STORE_PROV_INFO pStoreProvInfo
);

Note that the first five parameters are those that were passed as parameters to CertOpenStore.

Parameters

lpszStoreProvider
See CertOpenStore.
dwMsgAndCertEncodingType
See CertOpenStore.
hCryptProv
See CertOpenStore.
dwFlags
See CertOpenStore.
pvPara
See CertOpenStore.
hCertStore
The hCertStore parameter is the handle of the store in memory that has been opened, and can be used to make calls to other store-related API calls, such as CertAddSerializedElementToStore.
pStoreProvInfo
The pointer to the CERT_STORE_PROV_INFO to be updated. The data structure has been zeroed, and cbSize set before the call.

pStoreProvInfo->cStoreProvFunc is the count of callback functions that are implemented, and should be set last. Once set, all subsequent store calls, such as CertAddEncodedCertificateToStore will call the appropriate provider callback function.

Return Values

Returns TRUE if successful, FALSE if it was unable to open the store.


CertStoreProvCloseCallback

An application-defined callback function that is called by CertCloseStore when the store's reference count is decremented to zero.

void WINAPI CertStoreProvCloseCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN DWORD dwFlags
);

Parameters

hStoreProv
The provider specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
dwFlags
This parameter is the dwFlags that was passed as a parameter to CertCloseStore.


CertStoreProvDeleteCertCallback

An application-defined callback function that is called by CertDeleteCertificateFromStore before deleting a certificate from the store.

BOOL WINAPI CertStoreProvDeleteCertCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCERT_CONTEXT pCertContext,
  IN DWORD dwFlags
);

Parameters

hStoreProv
The provider specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCertContext
A pointer to the certificate context to be deleted.
dwFlags
This parameter is reserved for future use and is set to zero.

Return Values

Returns TRUE if it is okay to delete the certificate from the store. Otherwise, returns FALSE.


CertStoreProvDeleteCRLCallback

An application-defined callback function that is called by CertDeleteCRLFromStore before deleting the CRL from the store.

BOOL WINAPI CertStoreProvDeleteCRLCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCRL_CONTEXT pCrlContext,
  IN DWORD dwFlags
);

Parameters

hStoreProv
The provider-specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCrlContext
A pointer to the CRL context to be deleted.
dwFlags
This parameter is reserved for future use and is set to zero.

Return Values

Returns TRUE if it is okay to delete from the store. Otherwise, returns FALSE.


CertStoreProvReadCertCallback

An application-defined callback function that reads the provider's copy of the certificate context. If one exists, a new certificate context is created. Currently not called directly by the certificate store functions. However, it may be exported to support other providers.

BOOL WINAPI CertStoreProvReadCertCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCERT_CONTEXT pStoreCertContext,
  IN DWORD dwFlags,
  OUT PCCERT_CONTEXT *ppProvCertContext
);

Parameters

hStoreProv
The provider-specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pStoreCertContext
The context of the certificate to be read.
dwFlags
This parameter is reserved for future use and is set to zero.
ppProvCertContext
A pointer to a pointer to provider's copy of the certificate context. The context will be freed by calling CertFreeCertificateContext.

Return Values

Returns TRUE if the certificate was successfully read.


CertStoreProvReadCRLCallback

An application-defined callback function that reads the provider's copy of the CRL context. If one exists, a new CRL context is created.

Currently not called directly by the certificate store functions. However, may be exported to support other providers.

BOOL WINAPI CertStoreProvReadCRLCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCRL_CONTEXT pStoreCrlContext,
  IN DWORD dwFlags,
  OUT PCCRL_CONTEXT *ppProvCrlContext
);

Parameters

hStoreProv
The provider-specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pStoreCrlContext
The context of the CRL to be read.
dwFlags
This parameter is reserved for future use and is set to zero.
ppProvCrlContext
A pointer to a pointer to provider's copy of the CRL context. The context will be freed by calling CertFreeCRLContext.

Return Values

Returns TRUE if the CRL was successfully read.


CertStoreProvSetCertPropertyCallback

An application-defined callback function that is called by CertSetCertificateContextProperty before setting the certificate's property. It is also called by CertGetCertificateContextProperty when getting a hash property that needs to be created and then persisted via the set.

Upon input, the property hasn't been set for the pCertContext parameter.

BOOL WINAPI CertStoreProvSetCertPropertyCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCERT_CONTEXT pCertContext,
  IN DWORD dwPropId,
  IN DWORD dwFlags,
  IN const void *pvData
);

Parameters

hStoreProv
The provider specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCertContext
See CertSetCertificateContextProperty.
dwPropId
See CertSetCertificateContextProperty.
dwFlags
This parameter is the dwFlags that was passed as a parameter to CertSetCertificateContextProperty.
pvData
See CertSetCertificateContextProperty.

Return Values

Returns TRUE if it is okay to set the property.


CertStoreProvSetCRLPropertyCallback

An application-defined callback function that is called by CertSetCRLContextProperty before setting the CRL's property. It is also called by CertGetCRLContextProperty, when getting a hash property that needs to be created and then persisted via the set.

Upon input, the property hasn't been set for the pCrlContext parameter.

BOOL CertStoreProvSetCRLPropertyCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCRL_CONTEXT pCrlContext,
  IN DWORD dwPropId,
  IN DWORD dwFlags,
  IN const void *pvData
);

Parameters

hStoreProv
The provider specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCrlContext
See CertSetCRLContextProperty.
dwPropId
See CertSetCRLContextProperty.
dwFlags
This parameter is the dwFlags that was passed as a parameter to CertSetCRLContextProperty.
pvData
See CertSetCRLContextProperty.

Return Values

Returns TRUE if it is okay to set the property.


CertStoreProvWriteCertCallback

An application-defined callback function that is called by CertAddEncodedCertificateToStore, CertAddCertificateContextToStore and CertAddSerializedElementToStore before adding to the store. In addition to the encoded certificate, the added pCertContext might also have properties.

BOOL WINAPI CertStoreProvWriteCertCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCERT_CONTEXT pCertContext,
  IN DWORD dwFlags
);

Parameters

hStoreProv
The provider specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCertContext
See CertAddCertificateContextToStore.
dwFlags
CERT_STORE_PROV_WRITE_ADD_FLAG is set when this function is called by the following functions that add a certificate to the store:

CertAddEncodedCertificateToStore

CertAddCertificateContextToStore

CertAddSerializedElementToStore

Return Values

Returns TRUE if it is okay to update the store.


CertStoreProvWriteCRLCallback

An application-defined callback function that is called by CertAddEncodedCRLToStore, CertAddCRLContextToStore and CertAddSerializedElementToStore before adding to the store. In addition to the encoded CRL, the added pCrlContext might also have properties.

BOOL WINAPI CertStoreProvWriteCRLCallback(
  IN HCERTSTOREPROV hStoreProv,
  IN PCCRL_CONTEXT pCrlContext,
  IN DWORD dwFlags
);

Parameters

hStoreProv
The provider-specific value returned in CERT_STORE_PROV_INFO by CertDllOpenStoreProv.
pCrlContext
See CertAddCRLContextToStore.
dwFlags
CERT_STORE_PROV_WRITE_ADD_FLAG is used to specify when this function is called by the following functions that add a CRL to the store:

CertAddEncodedCRLToStore

CertAddCRLContextToStore

CertAddSerializedElementToStore

Return Values

Returns TRUE if it is okay to update the store.


Extending CertVerifyRevocation Functionality

Application developers that find it necessary to implement an installable revocation handler need to consider the following information.

For each certificate context supplied to CertVerifyRevocation in the rgpvContext array, an attempt is made to call a default revocation handler (function) that is associated with it. The contexts must contain enough information to allow the installable or registered revocation DLLs to find the revocation server. For certificates, this information would normally be conveyed in an extension such as the Internet Engineering Task Force's (IETF) AuthorityInfoAccess extension.

The handler function will check the certificate's revocation status. The certificates are examined sequentially, starting at the first one, rgpvContext[0]. CertVerifyRevocation makes no assumptions about the order of the contexts. For example, for certificates, CertVerifyRevocation doesn't assume a chain of certificates from an end-entity to a self-signed root, although this will often be the case.

The checks are discontinued if a certificate context is found to be revoked, or the revocation status could not be verified for a given context.


Default Revocation-Handler Functions

Default revocation-handler functions get installed or registered in the same manner as explained in OID Overview, with the following exceptions:

  • When installing a default revocation-handler function, call CryptInstallOIDFunctionAddress, with its rgFuncEntry[].pszOID parameter set to CRYPT_DEFAULT_OID.
  • When registering a default revocation-handler function, call CryptRegisterDefaultOIDFunction.

The following list describes how CertVerifyRevocation attempts to find the address of a default revocation-handler function to be called:

  1. A check is made for any installed handlers by making an iteration through the CRYPT_OID_VERIFY_REVOCATION_FUNC function's list of installed DEFAULT functions. To iterate through the list of installed DEFAULT functions, CryptGetDefaultOIDFunctionAddress is called with pwszDll = NULL.
  2. If no installed functions are found capable of doing the revocation verification, CertVerifyRevocation then checks for a registered handler by iterating through the CRYPT_OID_VERIFY_REVOCATION_FUNC function's list of registered DEFAULT DLLs. CryptGetDefaultOIDDllList is called to get the list. CryptGetDefaultOIDFunctionAddress is called to load the DLL.

If a function to handle the revocation check is still not found, then the search is abandoned, and CertVerifyRevocation returns FALSE and sets LastError, and the dwError member of pRevStatus, to CRYPT_E_NO_REVOCATION_CHECK or CRYPT_E_NO_REVOCATION_DLL.


Handler Return Value Requirements

When a function has been found that can perform the revocation verification check, it is called and passed the same parameters originally passed to CertVerifyRevocation, with the exception of rgpvContext[] and cContext. Because a called function has the option to process one or more of the contexts, rgpvContext[] and cContext are updated to specify the remaining count of contexts and the next context to be checked. Also, the cbSize member of pRevStatus has been checked to be equal to or greater than the size of CERT_REVOCATION_STATUS, and the remaining members have been zeroed.

A called revocation verification function reports back it's progress in the same manner that the CertVerifyRevocation return value is specified, with errors handled as follows:

If all the contexts were successfully checked and none were revoked, then TRUE should be returned, otherwise FALSE should be returned.

If FALSE is returned, the following actions should be taken:

  • If one of the contexts is found to be revoked, the index of the revoked certificate context should be returned in the dwIndex member of pRevStatus. Additionally, the dwError member of pRevStatus should be set to CRYPT_E_REVOKED. If the reason for revocation is known, the dwReason member of pRevStatus should be set to one of the predefined reasons. See CERT_REVOCATION_STATUS for a list of reasons.
  • If a context can't be checked for revocation, then the index of the unverified certificate context should be returned to the dwIndex member of pRevStatus. Additionally:
    • If the called function was capable of processing the context, but was unable to complete the revocation check, the dwError member of pRevStatus should be set to CRYPT_E_REVOCATION_OFFLINE.
    • If the called function was not capable of processing the context, the dwError member of pRevStatus should be set to CRYPT_E_NO_REVOCATION_CHECK.

Note CertVerifyRevocation sets LastError to the value returned in the dwError member of pRevStatus.


Introduction to CSPs

This document defines the cryptographic service provider interface and describes the procedure by which custom cryptographic service providers (CSPs) are created.

A tight focus on CSPs is maintained throughout this document. The following subjects are not covered:

  • Cryptography
  • Cryptographic protocols and standards
  • Cryptographic application programming
  • Windows programming

Even though these subjects are not discussed here, you will need to be familiar with most of them in order to implement a good CSP. Please refer to Related Documentation for a list of additional reading. This document assumes that you have already read CryptoAPI 2.0 in the Microsoft® Platform SDK.

As mentioned in the CryptoAPI 2.0 section of the Microsoft Platform SDK, cryptographic service providers (CSPs) contain implementations of cryptographic algorithms and standards.

Every CSP consists of, at a minimum, a dynamic-link library (DLL) that exposes each of the functions in CryptoSPI. Many CSPs will be implemented (at least in part) in a Win32 service program, managed by the Win32 service control manager; or in hardware, such as a smart card or secure coprocessor. In either case, the DLL may merely act as a pass-through layer, facilitating the communication between the operating system and the actual CSP implementation.


Related Documentation

Additional documents that may help you understand cryptography and the associated security issues include:

  • Schneier, Bruce Applied Cryptography, John Wiley & Sons, 1996.
  • The Microsoft Platform SDK, CryptoAPI 2.0, Microsoft , 1997, located at http://www.microsoft.com.
  • Stinson, D. R. Cryptography: Theory and Practice, CRC Press 1995.
  • Anderson, R. "Why Cryptosystems Fail," Communications of the ACM, v. 37, n. 11, Nov 1994, pp. 32-40.
  • RSA Laboratories, Public-Key Cryptography Standards, RSA Data Security, November 1993.
  • Cormen, Thomas H.; Charles E. Leiserson; Ronald L. Rivest. Introduction to Algorithms, MIT Press, 1990.
  • Davies, D.W. and W.L. Price. Security for Computer Networks, John Wiley & Sons, 1989.
  • Denning, Dorothy E., Cryptography and Data Security, Addison-Wesley, 1982.


Architecture of a Cryptographic Service Provider (CSP)

This chapter outlines the internal structure of a typical CSP, and explains some of the assumptions that are implicit in the CryptoAPI/CryptoSPI design. While it's understood that every CSP will be structured a little differently, most of the material in this chapter should apply to all of them.


Architecture Overview

As the following illustration shows, applications don't communicate with CSPs directly, but instead make calls to the CryptoAPI (exposed by the operating system's Advapi32.dll file). The operating system filters these function calls, and passes them on to the appropriate CSP through the CryptoSPI.

Applications refer to data objects within the CSP via handles. Some examples are key containers, hash objects, session key objects, and public/private key pair objects. It is important to realize that these handles are opaque from both sides. That is, the handle that the application sees is not the same one that the CSP exports. For various reasons, the operating system layer performs indirection on all data object handles.


Entry Points

Every CSP must support the following DLL entry points:

  • CPAcquireContext
  • CPCreateHash
  • CPDecrypt
  • CPDeriveKey
  • CPDestroyHash
  • CPDestroyKey
  • CPEncrypt
  • CPExportKey
  • CPGenKey
  • CPGenRandom
  • CPGetHashParam
  • CPGetKeyParam
  • CPGetProvParam
  • CPGetUserKey
  • CPHashData
  • CPHashSessionKey
  • CPImportKey
  • CPReleaseContext
  • CPSetHashParam
  • CPSetKeyParam
  • CPSetProvParam
  • CPSignHash
  • CPVerifySignature

Note All of these functions must be declared with the WINAPI key word.

These functions compose the CryptoSPI, and should look familiar, because they correspond directly to the cryptographic functions in CryptoAPI. CryptoAPI contains one additional function, CryptSetProvider, that is not passed through to the CSP.


Persistent Data Objects

Every CSP is responsible for storing public/private key pairs from session to session, in some sort of persistent memory. A CSP implemented completely in software might store these (encrypted) in the Windows Registry; those with a hardware component will likely store the key pairs in tamper-resistant hardware.

The key pairs are stored in logical data objects known as key containers. The CSP maintains one key container for each user (or client) that uses the CSP. Each key container can store one key pair of each type that the CSP recognizes. For example, the Microsoft® Base Cryptographic Provider recognizes two key pair types, the key exchange key pair and the digital signature key pair.

Several key containers may be "open" at any given time (either by a single application or multiple ones), but every call to a CryptoSPI function will specify the key container that is to be used via the first parameter to the function. This is illustrated by the following drawing.

Note In the context of CryptoSPI, the HCRYPTPROV data type is used to represent a handle to a particular key container within the CSP. This is slightly different than in the CryptoAPI context, where handles of the HCRYPTPROV data type also specify the CSP that is to be used.


Volatile Data Objects

CSPs should maintain session key objects and hash objects in volatile memory. These objects are created respectively via the CPGenKey and CPCreateHash functions, and destroyed via the CPDestroyKey and CPDestroyHash functions. These objects should also be destroyed when their associated key container (or "user context") is released via the CPReleaseContext function.


Extending CryptoAPI

The CryptoAPI has been designed very carefully to be easily extensible. New types and parameters can be defined by any CSP author so as to make the CryptoAPI bend to the requirements of a wide variety of situations. Among the items that can be extended are:

  • Provider types—Every provider type represents a particular family or type of cryptographic services. It is envisioned that many new provider types will be defined, each servicing a particular niche.
  • Provider parameters—These packages of data are sent/received via CPSetProvParam and CPGetProvParam. Defining new parameters allows your CSP to be configured in ways not thought of by the CryptoAPI designers.
  • Algorithm identifiers—New symmetric, public-key, and hash algorithms can be defined at any time. The enumeration facilities of CPGetProvParam allow applications to dynamically become aware of them.
  • Public/private key pair types—As of this writing, only signature and key exchange key pair types have been defined. New types can be defined as needed.
  • Key blob types—New key blob types can be defined, potentially permitting session keys, public keys, and public/private key pairs to be exchanged in a very flexible manner using the CPExportKey and CPImportKey functions.
  • Key parameters—These packages of data are sent/received via CPSetKeyParam and CPGetKeyParam. New parameters can be defined, allowing for the support of many different types of keys.
  • Hash object parameters—These packages of data are sent/received via CPSetHashParam and CPGetHashParam. New parameters can be defined, allowing for the support of many different types of hashes.
  • Flag values—Every CryptoAPI/CryptoSPI function has a dwFlags parameter. New flags can be defined so that the behavior of each function can be modified as necessary. Extensions to CryptoAPI should be made in a responsible manner. Before defining a bunch of new parameters and algorithm types, you should consult with the people at Microsoft, so that:
    • Common CryptoAPI extensions can be identified and placed into the standard Win32 WINCRYPT.H header file.
    • Namespace collisions can be avoided.
    • A determination can be made as to whether the extension is really required, or whether the particular operation can be achieved with the current API.

Important If you want your CSP to be compatible with applications developed for the Microsoft Base Cryptographic Provider, you must support all of the preceding items as they described in the CryptoAPI Reference and in this CSP Reference. For the details, see the CryptoAPI Reference Overview and the RSA/Full CSP Reference Overview.


Writing a CSP

Once you have decided which cryptographic algorithms and data formats are to be included in your CSP and obtained implementations for each of them, putting together a CSP is comparatively straightforward.

The procedure for creating a CSP is outlined as follows:

  1. Create a DLL that exports all of the CryptoSPI functions.

    If your CSP has hardware components, this might also involve writing a smart card device driver and/or the embedded code that runs on the card, but you are on your own with regard to generating the hardware-specific components.

  2. Write a setup program for the CSP that creates the appropriate Registry entries.
  3. Test the CSP. This can only be done using the CSP Developer's Kit, and involves the following sub-steps:
    1. Sign the CSP with the Sign.exe utility, producing a debug signature (.SIG) file.
    2. Install the CSP using the setup program mentioned in step 2.
    3. Run test code that makes calls to the CSP via CryptoAPI.
  4. Have the CSP signed by Microsoft®. This will enable the CSP to be used with the released versions of Microsoft Windows NT® or Microsoft Windows® 95. This procedure is described in Getting CSPs Signed.
  5. Test the CSP again. This is the same as step 3, except that the "real" signature and the release version of Windows NT are used.


Creating the CSP DLL

A CSP DLL is created just as any other DLL. Because this procedure is adequately explained in Windows programming books, it is not discussed here.

Every CSP DLL must export all of the CryptoSPI functions. If the CSP does not support a particular function, the function should return the E_NOTIMPL error code. This is a fairly common situation; for example, a CSP that just does signature verification will not support the data encryption functions.


Using Auxiliary DLLs

Some CSPs may be composed of more than one DLL. In this case, all of the DLLs must be signed by Microsoft, in the same manner as if there is only one DLL. This has some run-time complications, which are discussed in Service Provider Functions along with the CPAcquireContext function.


Writing the CSP Setup Program

At a minimum, the CSP Setup program must copy the CSP DLL to a directory pointed to by the PATH environment variable and create the appropriate Registry entries.


Registering the CSP

The following Registry entries "register" the CSP with the operating system.

HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Cryptography
Defaults
Provider
<CSP name>
>Image Path:REG_SZ:<CSP DLL name>
>Signature:REG_BINARY:<digital signature>
 >Type:REG_DWORD:<CSP type>

The "CSP name" entry must be the textual name of the CSP. If the CSP has been signed by Microsoft, this name must exactly match the CSP name that was specified in the Export Compliance Certificate (ECC). For information on the ECC, see Getting CSPs Signed.

The "Image Path" entry must be set to the name of the CSP DLL. Optionally, a fully qualified path, such as "c:\myx\rsabase.dll" can also be specified here. In this case, the CSP DLL need not be placed in a directory pointed to by the PATH environment variable.

The "Signature" entry must contain a digital signature for the CSP DLL. This signature can either be created with the Sign.exe utility (the debug signature) or obtained from Microsoft (the release signature). The Sign.exe utility is discussed in Using the Sign.exe Utility.


Setting the Machine Default CSP

One machine default CSP can be specified for each CSP type. This entry is used when an application calls the CryptAcquireContext function with only a CSP type specified, and no user default CSP Registry entry exists.

The typical CSP Setup program will install its CSP as the machine default.

The following Registry entry sets the machine default CSP:

HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Cryptography
Defaults
Provider Types
Type <CSP type>
 >Name:REG_SZ:<CSP name>

The "CSP type" portion of the key name must be in decimal format, and exactly 3 digits in length. For example, if the CSP is of type 25, the key name would be "Type 025".

The "Name" entry must be set to the textual name of the CSP. This must exactly match the "CSP name" Registry key discussed in the previous section.


Setting the User Default CSP

One user default CSP can be specified for each CSP type. This entry is used when an application calls the CryptAcquireContext function with only a CSP type specified.

The user defaults are stored in the Registry's HKEY_CURRENT_USER window, so the CSP Setup program can set this value only if the actual end user is currently logged on to the computer. In any case, the end user should be consulted and/or informed whenever the user default CSP is changed.

The user default CSP is to be set via the CryptSetProvider function, which internally sets the following Registry entry:

HKEY_CURRENT_USER
Software
Microsoft
Cryptography
Providers
Type <CSP type>
 >Name:REG_SZ:<CSP name>

The "CSP type" portion of the key name must be in decimal format, and exactly 3 digits in length.

The "Name" entry must be set to the textual name of the CSP. This must exactly match the "CSP name" Registry key discussed earlier in this chapter.


Testing the CSP

Your CSP DLL must be signed each time that it is built, and the signature placed appropriately in the Registry. It is probably a good idea to incorporate this procedure into your make file, so that no steps are ever forgotten.


Using the Sign.exe Utility

The Sign.exe utility is used to sign CSP DLLs. Given a DLL file, it will produce a signature file, whose contents can be placed into the Registry as discussed in the previous section. Sign.exe takes three arguments, as shown below:

sign {s|v} <filename> <signature file>

The first argument must be "s" if a signature file is to be generated, and "v" if an existing signature file is to be verified against the DLL file. The second argument must be the fully qualified file name of the DLL file, and the third argument the fully qualified file name of the signature file.

If the CSP DLL file is called Myxcsp.dll, the following command can be used to generate a signature file for it (called Myxcsp.sig).

sign s myxcsp.dll myxcsp.sig


Getting CSPs Signed

This chapter describes the CSP signature process and Microsoft's policy on digitally signing CSPs for vendors in and outside of North America (the United States and Canada).

Every CSP must be digitally signed by Microsoft in order to be recognized by the operating system. The primary purpose of the digital signature is the protection of the system and its users - the operating system validates this signature periodically to ensure that the CSP has not been tampered with. A secondary effect of the digital signature is that it separates applicable export controls on the CSP from the host operating system and applications, thereby allowing broader distribution of encryption-enabled products than would be possible under other circumstances. Generally, U.S. export law limits the export outside the U.S. or Canada of products that host strong encryption or an open cryptographic interface. The digital signature requirement effectively prevents arbitrary use of CryptoAPI, and allows export of the host operating system and CryptoAPI-enabled applications. By removing encryption services from host systems and applications, CryptoAPI places the burden of U.S. encryption export restrictions squarely on the CSP vendor, which is subject to those controls regardless.


CSP Signing Policy - Overview

Microsoft's interest in the CSP signing process is to maintain the integrity of system security and the exportability of CryptoAPI-enabled systems and applications, and to exercise due diligence under prevailing U.S. export controls. The CSP signing policy makes several major distinctions based on Microsoft's obligations under U.S. export law. First, it distinguishes between CSPs developed in North America from those developed elsewhere. Second, it distinguishes between CSPs intended for sale or distribution within North America only from those intended for export or sale outside North America. Generally the signing policy requirements for CSPs intended for use only within North America are fewer than for CSPs intended for export; and because U.S. export law restricts the export of any encryption technology or services, the requirements and restrictions on CSPs from vendors outside North America intended for use outside North America are greater still. Each of these scenarios is described in greater detail in the following sections.

Microsoft will sign CSPs subject only to the limitations of U.S. export controls. We will sign CSPs from competitors. At present we will sign CSPs at our facilities in Redmond, Washington, USA.


CSP Signing Policy - North American CSP Vendors

CSP vendors pursuing CSP development within North America must complete and return an Export Compliance Certificate ("ECC") to Microsoft. Microsoft will make every effort to review the ECC and sign CSPs as expeditiously as possible. Exact time frames for review and signing depend on the circumstances of your request. A copy of the ECC is included at the end of this section.

North America Only CSP If you do not intend to distribute your CSP outside North America, complete the ECC and certify that you will distribute your CSP only in the U.S. or Canada. Return the ECC to Microsoft. When Microsoft has had a chance to review and verify the ECC, you'll be contacted with information on arrangements to sign your CSP.

CSP Intended for Export If you do plan to export your CSP, you must obtain export approval from a U.S. or Canadian export licensing authority or claim an exemption under U.S. export law; you must complete the ECC with evidence of your export approval or exemption, and certify that you intend to export your CSP from the U.S. or Canada. Return the ECC to Microsoft. Microsoft may independently confirm export approval, and when confirmation is complete, you'll be contacted with information on arrangements to sign your CSP.

Vendors should consult legal counsel or U.S. export authorities to determine whether an export approval or exemption applies to their CSP. See Assistance and Feedback later in this section.

Canadian CSP vendors should note that because Canadian export controls are not entirely consistent with U.S. export controls; U.S. and Canadian export authorities may need to agree whether a given CSP should be signed. Therefore an approval to export from Canada may or may not be sufficient for Microsoft to sign the CSP.

Before Microsoft applies a digital signature to any CSP - whether it is intended for use in North America or elsewhere - Microsoft must receive an original signed ECC. However, Microsoft can initiate review and confirm export approval against a fax copy of the complete ECC.

Ordinarily Microsoft does not need to receive the actual CSP to complete signing, but can sign a message digest (hash) of the CSP itself. It is possible that a U.S. export license or other export approval for a CSP intended for export may require independent or government verification of the CSP's implemented security features prior to signing, which would be the responsibility of the CSP vendor.


CSP Signing Policy - CSP Vendors outside North America

This section assumes that a CSP vendor from outside North America has already received the CSPDK under an appropriate U.S. export license; those who have not yet received the CSPDK can contact Microsoft (cspsign@microsoft.com) for information on the CSPDK license process.

Because all of the required certifications are completed during the U.S. export license process, when a CSP vendor from outside North America is ready to have their CSP signed its not necessary to complete an Export Compliance Certificate or other documentation. They should simply notify Microsoft when they are ready, or preferably notify Microsoft approximately two to three weeks prior to when the CSP may be ready to sign. Microsoft will use the time to verify the request against any possible terms and conditions of the export license covering the CSP development. When confirmation is complete, you'll be contacted with information on arrangements to sign your CSP.

Its possible that a U.S. export license or other export approval for a CSP intended for export may require independent or government verification of the CSP's implemented security features prior to signing, which would be the responsibility of the CSP vendor. It may also be a condition of the U.S. export license that Microsoft receives the actual CSP for signing, and not just a hash.

At present we will sign CSPs at our facilities in Redmond, Washington, USA. It is possible in the future that we will sign CSPs at approved locations in foreign countries, at which time we will offer CSP vendors from outside North America the option of offshore signing.

In summary, Microsoft will sign CSPs for vendors outside North America subject only to the limitations of U.S. export controls and other national controls on this technology. We will sign CSPs from competitors. Microsoft will make every effort to review signing requests and sign CSPs as expeditiously as possible. Exact time frames for review of signing requests and CSP signing depend significantly on whether the U.S. export license permitting the CSP development set down any conditions for review or confirmation of the CSP's implemented security features.


CSP Signing Program - Limitations and Provisos (All Vendors)

Microsoft's interests in applying signatures to CSPs are to maintain the integrity of system security, ensure the exportability of CryptoAPI-enabled systems and applications, and to exercise due diligence under prevailing U.S. and other national export controls. Any disclosure requested by Microsoft is used solely to determine whether export approval is required, or if sufficient export approval exists, for Microsoft to sign a vendor's CSP.

Microsoft obtains no right to any CSP by virtue of signing it. Neither does Microsoft assume any responsibility for the CSPs they sign. The CSP vendor is wholly responsible for the distribution, disposition and possible end-use of its CSPs, including any possible export or diversion of CSPs outside North America or licensed destinations.

Microsoft relies on the CSP vendor's completion of the ECC, CSPDK Export Questionnaire and other documents as to the intended distribution, disposition and use of the CSP in or out of North America, and as an assurance that the vendor will exercise due diligence over the operation, sale, or transfer of its CSP using the Microsoft CryptoAPI. If a vendor's intention changes after a CSP is signed (e.g. it opts to export a CSP signed by Microsoft with the understanding that the CSP was for use in North America only), the vendor is responsible for compliance with U.S. export regulations.

The digital signature applied to CSPs in no way grants U.S. export approval or any other form of legal approval for use of a CSP in any national or international context. In particular, Microsoft has no role in the U.S. export approval process of a North American vendor's CSP: U.S. export approval (by license, classification, or exemption) is a separate requirement that CSP vendors must satisfy independently of the digital signature process, and it must precede the signature process when the CSP is intended for use outside North America. Microsoft's involvement in U.S. export issues will be limited to applying for licenses to export to foreign vendors the CSPDK and to sign their CSPs, as well as to perform due diligence verification that licensed CSP vendors comply with the terms of any U.S. export license.

Microsoft cannot provide the CSPDK to, or sign CSPs from, any vendor who is engaged in a prohibited activity, who is from a prohibited destination, or who is a prohibited party as defined by U.S. law (including the Export Administration Regulations and International Traffic in Arms Regulations). US export laws prohibit Microsoft from providing the CSPDK or signing any CSP if we have reason to know that a given vendor may intentionally violate US export laws, despite a written assurance to the contrary.

The description of U.S. export controls in this chapter is provided for general information purposes only. This document reflects the U.S. export laws and CSP signing program in effect as of April 1997. Export laws are subject to rapid change; therefore this document may not accurately represent current export law. Please consult legal counsel and the appropriate export control agencies to ensure compliance with U.S. and local export laws.


Background - U.S. Export Controls and CryptoAPI

As of January 1, 1997, export of the CSPDK or provision of CSP signing services outside the United States is regulated under "EI controls" of the Export Administration Regulations (EAR, 15 CFR 730-744) of the U.S. Commerce Department, Bureau of Export Administration (BXA). EI controls are the current equivalent of ITAR munitions export controls that applied to the CSPDK and CSP signing services prior to January 1st. EI controls require a Commerce export license prior to any export, transmission, provision or shipment of the CSPDK product or CSP signing service to any country, other than Canada, or to any person, entity or end user subject to U.S. export restrictions. The Commerce export license process and EI controls are described on BXA's web site at http://www.bxa.doc.gov/encstart.htm.


CSPs

The export status of specific CSPs may vary, but generally they are subject to review and approval on a case by case basis by the U.S. Commerce Department, Bureau of Export Administration.


CryptoAPI and the Microsoft Base Cryptographic Provider

Microsoft® Windows NT® with the Microsoft Cryptographic API and the Microsoft Base Cryptographic Provider was transferred from State to Commerce jurisdiction by ODTC Case CJ 128-95, and qualifies for export under License Exception TSU (formerly GTDU) and the General Software Note (GSN) listed in Supplement 2 to Part 774 of the U.S. Commerce Export Administration Regulations. A subsequent transfer covers Microsoft Windows® 95 with the CryptoAPI and the Base Cryptographic Provider. These products may be exported to all destinations and users except countries, persons, entities, or end users subject to U.S. export restrictions. Restricted countries currently include, but are not necessarily limited to, Cuba, Iran, Iraq, Libya, North Korea, Sudan and Syria. Restricted persons and entities include but are not necessarily limited to anyone whose export privileges have been suspended, revoked, or denied by the U.S. Bureau of Export Administration or any other federal agency.

U.S. export laws restrain Microsoft and other U.S. companies from offering or enabling strong data encryption in their products intended for export from the U.S. or Canada. Software with data encryption, or software with APIs to provide cryptographic services, are treated as highly restricted commodities. By prohibiting foreign sale of these products to all but a few entities outside North America, the U.S. government limits distribution of such products to the U.S. and Canada and eliminates virtually all foreign markets for most vendors, thereby removing much of the incentive to implement these features in the first place. Generally speaking, U.S. export restrictions have been a very effective deterrent to the proliferation of strong encryption in mass-market software in the U.S. and abroad.

An open cryptographic API allowing any vendor to implement any CSP might be very useful to security providers, but it would make the host operating system with the cryptographic API ineligible for export from the U.S. or Canada. To ensure that CryptoAPI-enabled Microsoft operating systems are and will remain exportable, Microsoft does not permit open access to these APIs. Microsoft has implemented the CSP signing policy to meet the dual objectives of providing as many vendors as possible a secure and flexible approach to enabling cryptographic services, while maintaining the foreign availability of Microsoft operating systems.

The digital signature requirement separates possible export controls on the CSP from the host operating system and applications, thereby allowing broader distribution of encryption-enabled products than would be possible under other circumstances. The signature effectively prevents arbitrary use of CryptoAPI, which ensures the continued exportability of the host operating system. By removing encryption services from host systems and applications, the burden of U.S. encryption export restrictions is placed squarely on the cryptographic provider which is already subject to these controls with respect to any CSP it markets, whether or not the CSP functions through CryptoAPI.

Microsoft's program for distribution of the CSPDK and CSP signing policy are specifically designed to minimize the impact of U.S. export laws to the greatest extent we think is possible today: they specifically do not interfere with the development of CSPs for use in North America; the CSP signing policy expects vendors to perform due diligence in the licensing of their CSPs when those CSPs are intended for export from the U.S. or Canada; and the CSPDK distribution program and CSP signing policy comply with existing U.S. export laws for the provision of encryption products (CSPDKs) and services (CSP signatures) to vendors outside the U.S. or Canada.


Assistance and Feedback

Questions and comments about the CSP signing mechanism, signing procedures and CryptoAPI licensing policy can be directed via email to cspsign@microsoft.com, or to

Ryan Bolz, CryptoAPI Program Manager
Microsoft Corporation
One Microsoft Way
Redmond WA 98052-6399 USA

FAX 425-936-7329

CSP Vendors may wish to consult the U.S. Commerce Department, Bureau of Export Administration, Office of Exporter Services for assistance in the classification and/or export licensing of CSPs for export from the U.S. The Commerce export license process, encryption export controls and points of contact are described on BXA's web site at http://www.bxa.doc.gov/encstart.htm, or call for Encryption Assistance at PH 202-482-5400.


Export Compliance Certificate (ECC)

EXPORT COMPLIANCE CERTIFICATE

For CSP Signing Services to North American Vendors

WHO SHOULD COMPLETE THIS DOCUMENT The Export Compliance Certificate ("ECC") is intended for CSP vendors with operations in the U.S. or Canada (hereafter 'North America') pursuing CSP development within North America, who seek to have Microsoft or a third-party designated by Microsoft digitally sign a vendor's CSP to enable it to access the Microsoft CryptoAPI. If you are a vendor located outside North America an export license agreement or other arrangement may replace the ECC.

DISCLAIMER AND NOTICE This document is used solely to determine whether export approval is required, or if sufficient export approval exists, for Microsoft to sign CSPs. Microsoft's interests in applying signatures to CSPs are to maintain the integrity of system security, ensure the exportability of CryptoAPI-enabled systems and applications, and to exercise due diligence under prevailing U.S. and other national export controls. Microsoft obtains no right to any CSP by virtue of signing it. Neither do we assume any responsibility for the CSPs we sign. The CSP vendor is wholly responsible for the distribution, disposition and possible end-use of its CSPs, including any possible export or diversion of CSPs outside North America or licensed destinations. The digital signature applied to CSPs in no way grants U.S. export approval or any other form of legal approval for use of a CSP in any national or international context. Microsoft has no role in the U.S. export approval process of a vendor's CSP: U.S. export approval (by license, classification, or exemption) is a separate requirement that CSP vendors must satisfy independently of the digital signature process, and it must precede the signature process when the CSP is intended for use outside North America.

CSP SIGNING CRITERIA AND VENDOR INSTRUCTIONS Microsoft will sign CSPs subject only to the limitations of U.S. export controls. We will sign CSPs from competitors. Microsoft will make every effort to complete ECC review and sign CSPs as expeditiously as possible. Exact time frames for review and signing depend on the circumstances of your request. Ordinarily Microsoft does not need to receive the actual CSP to complete signing, but can sign a hash of the CSP itself.

  • North America Only CSP If you don't intend to distribute your CSP outside North America: complete the ECC and certify that you will distribute your CSP only in the U.S. or Canada. Return the ECC to Microsoft. When you are ready, make an appointment for Microsoft to sign your CSP.
  • CSP Intended for Export If you do plan to export your CSP: obtain export approval from a U.S. or Canadian export licensing authority, complete the ECC with evidence of your export approval and certify that you intend to export your CSP from the U.S. or Canada. Return the ECC to Microsoft. Microsoft may independently confirm export approval, and when confirmation is complete, we'll arrange an appointment for Microsoft to sign your CSP.

    Canadian CSP vendors should note that because Canadian export controls are not entirely consistent with U.S. export controls; U.S. and Canadian export authorities may need to agree whether a given CSP should be signed. Therefore an approval to export from Canada may or may not be sufficient for Microsoft to sign the CSP.

Sign and Return to Microsoft Before Microsoft signs any CSP it must receive an original signed ECC with sufficient information to evaluate the request. Return ECCs to Microsoft Corporation, Attn: Ryan Bolz, One Microsoft Way, Redmond, WA 98052-6399. Questions? Email cspsign@microsoft.com.

SECTION I - GENERAL INFORMATION

All North American (U.S. and Canada) CSP vendors must complete this section

A. VENDOR INFORMATION Please give the physical address where CSP development has taken or will take place.

B. CSP INFORMATION Please supply sufficient information to identify your CSP by name and to categorize its cryptographic functions. Provide a separate Export Compliance Certificate for each CSP you need signed.

C. INTENDED DISTRIBUTION FOR THIS CSP At the time of this certification the vendor intends the above-described CSP for distribution, disposition or use (check one):

SECTION II - EVIDENCE OF EXPORT APPROVAL

Complete this section only if the described CSP is intended for distribution outside of North America (U.S. and Canada). Otherwise skip to Section III. For export approval, consult legal counsel or relevant export authorities. Commerce export controls are described on their web site at http://www.bxa.doc.gov/encstart.htm.

A. EXPORT CONTROL JURISDICTION FOR THIS CSP Check one of the following:

B. EXPORT APPROVAL INFORMATION Check any type of export approval that you have obtained for this CSP and wish to cite as evidence of export approval. If the CSP is intended for use outside North America, Microsoft cannot sign the CSP without evidence of export approval. You may optionally attach a copy of your export license, CJ/CCATS confirmation, or other export approval. The export approval must correspond to the Product Name and Version cited above.

SECTION III - EXPORT NOTICES

Vendor must execute the signature portion of the ECC acknowledging US export controls as they may apply to their CSP, and attesting to the accuracy of the information they provide herein.

*export notice for csp vendors certifying that their csp is for distribution, disposition, or use solely in north america: csp Vendor acknowledges that their CSP is subject to US export control laws and regulations. CSP Vendor certifies that it does not intend to export or re-export the CSP named above outside of North America. If the CSP Vendor subsequently decides to export the CSP outside of North America by any means (including physical or electronic distribution), CSP Vendor agrees to obtain U.S. export approval. CSP Vendor is wholly responsible for such export, distribution, disposition and possible end-use of their CSP outside of North America, including complying with all US export or other national controls over their CSP modules, and that Microsoft assumes no responsibility or liability for CSP Vendor's failure to obtain required export approvals.

**export notice for csp vendors certifying that their csp is for distribution, disposition, or use outside of north america: csp Vendor acknowledges that their CSP is subject to US export control laws and regulations. CSP Vendor certifies that it intends to export or re-export the CSP named above outside of North America. CSP Vendor further acknowledges that it is wholly responsible for such distribution, disposition and possible end-use of its CSP outside of North America, including complying with all US export or other national controls over the CSP modules, and that Microsoft assumes no responsibility or liability for CSP Vendor's failure to obtain required export approvals.

If "Company Name" or a company address is filled in below, then the individual signing the ECC represents that he/she has authority to execute this agreement on behalf of such company. This ECC does not otherwise amend or alter the End-User License Agreement for the CryptoAPI CSP Development Kit (CSPDK) previously signed and completed by the Vendor.

IN WITNESS WHEREOF, Recipient has caused this Export Compliance Certificate to be executed by its duly authorized representative, and that the information provided herein is true to the best of his/her knowledge.


Interoperability with RSA CSPs

This chapter describes the implementation details to which all PROV_RSA_FULL and PROV_RSA_SIG providers must conform. Because the PROV_RSA_SIG provider type is a subset of PROV_RSA_FULL, not all of the material in this chapter is applicable to PROV_RSA_SIG providers.

The information in this chapter is included primarily for use by persons writing their own CSP, but may be of interest to some advanced application developers as well.

This section contains topics in five major areas:

  • Supported algorithms. A minimum set of algorithms must be supported by all PROV_RSA_FULL and PROV_RSA_SIG providers.
  • Key blob formats. A standard encoding scheme is defined for key blobs. This enables session keys and public keys to be exchanged between CSPs, even if the CSPs come from different vendors.
  • Deriving session keys. The procedure whereby session keys are derived from hash values is defined, so that given the same base data, every CSP will be able to generate exactly the same session key from it.
  • Hashing session keys. The procedure whereby session keys are hashed is defined, so that given the same session key, every CSP will be able to generate exactly the same hash value from it.
  • Digital signature mechanics. The mechanics of digital signatures (as well as the signature format) are defined, so that different CSPs can verify each other's signatures correctly.


Supported Algorithms

Every CSP of type PROV_RSA_FULL or PROV_RSA_SIG must support a minimum set of algorithms. Additional algorithms can be implemented as well, although this is discouraged. For the algorithms that must be supported to be interoperable with Microsoft Cryptographic Service Providers, see Microsoft Cryptographic Service Providers.


Public-Key Algorithms

All PROV_RSA_FULL and PROV_RSA_SIG providers use the RSA Public-Key Cipher for both digital signatures and key exchange. Two public/private key pairs are defined: the signature key pair and the exchange key pair. The exchange key pair can be used both to exchange session keys and to perform/verify digital signatures.

Although the Microsoft Base Cryptographic Provider uses 512-bit public/private keys, this is not a requirement. Your CSP is perfectly free to use larger keys, although this may make it subject to export control. For more information on export control, see Getting CSPs Signed.

The CPVerifySignature function of all CSPs must be able to verify signatures of up to 2048 bits, regardless of the size of the signatures produced by CPSignHash. This ensures that the CSP will be able to validate all compatible certificates, even those signed with very large keys. This requirement may be difficult for CSPs implemented in hardware packages with limited memory, so it may be necessary for some hardware CSPs to implement a signature verification algorithm within the primary DLL.


Symmetric Encryption Algorithms

Every CSP of type PROV_RSA_FULL or PROV_RSA_SIG must provide an implementation of the RC2 block cipher and the RC4 stream cipher. These algorithms are used by the session keys to perform the encryption and decryption of bulk data.

The Microsoft Base Cryptographic Provider uses 40-bit session keys, with 88 bits of salt (128 bits total). Your CSP is free to use larger keys, although this can make exporting your CSP rather difficult. For more information on export control, see Getting CSPs Signed.

If your CSP does use session keys larger than 40-bits, this will tend to make key exchange between your CSP and the Microsoft Base Cryptographic Provider rather difficult.


Hashing Algorithms

Every CSP of type PROV_RSA_FULL or PROV_RSA_SIG must provide implementations of both the MD5 and the SHA hash functions. In addition, having your CSP support the MD2 algorithm might be a good idea, if compatibility is important to you. To be interoperable with the Microsoft Cryptographic Service Providers, the SSL3 Client Authentication algorithm must be supported as well (For additional information see Microsoft Cryptographic Service Providers and SSL3 Client Authentication Algorithm).


Key Blob Formats

Key blobs are the data structures that store keys when they are not inside of a CSP. Every key blob consists of one or more fixed-length header structures, followed by the key data itself. This key data is variable in length, and often encrypted.

Each key blob consists of binary data. The size of a key blob will vary depending on the blob type and the key size.

Unless stated otherwise, all multibyte numbers are stored in little-endian format, meaning that the first byte of a number is the least significant and the last byte is the most significant. This is the most common format for computers running Microsoft Windows®.


The BLOBHEADER Structure

The BLOBHEADER structure is located at the front of every key blob. This is not limited to the key blobs generated by the PROV_RSA_BASE and PROV_RSA_SIG provider types. Any additional key blob types that are defined should also specify that each key blob start with this structure.

This structure contains fields that indicate the key blob type and the algorithm that the key uses.

typedef struct _PUBLICKEYSTRUC {
    BYTE   bType;
    BYTE   bVersion;
    WORD   Reserved;
    ALG_ID aiKeyAlg;
} ,PUBLICKEYSTRUC;

The following table describes each of the fields in the BLOBHEADER structure.

Field | Description
bType | Key blob type. The only blob types currently defined are the public key blob, private key blob, and simple blob types. Other key blob types will be defined as needed. Public key blobs are used to transport RSA public keys, private key blobs are used to transport RSA public/private key pairs, and simple blobs are used to transport session keys.
bVersion | Version number of the key blob format. This currently must always have a value of "0x02".

Reserved | These 2 bytes are reserved for future use, and should be zero.
aiKeyAlg | Algorithm identifier for the key contained by the key blob. Some examples are CALG_RSA_SIGN, CALG_RSA_KEYX, CALG_RC2, and CALG_RC4. Not all algorithm identifiers are valid with all blob types. For example, you would never export an RC4 key into a public key blob.


Public Key Blobs

Public key blobs (type PUBLICKEYBLOB) are used to store RSA public keys. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];

Notice that public key blobs are not encrypted, but contain public keys in plaintext form.

The RSAPUBKEY structure contains information specific to the particular public key contained in the key blob. It is defined as follows:

typedef struct _RSAPUBKEY {
    DWORD magic;
    DWORD bitlen;
    DWORD pubexp;
} RSAPUBKEY;

The following table describes each of the fields in the RSAPUBKEY structure.

Field | Description
magic | This should be set to "RSA1" (0x31415352) for public keys and to "RSA2" (0x32415352) for private keys. Notice that the hex values are just an ASCII encoding of "RSA1" and "RSA2."
bitlen | Number of bits in the modulus. In practice, this must always be a multiple of 8.
pubexp | The public exponent.

The public key modulus data is located directly after the RSAPUBKEY structure. The size of this data will vary depending on the size of the public key. The number of bytes can be determined by dividing the value of the bitlen field of RSAPUBKEY by 8.


Sample Public Key Blob

The following hex dump shows a sample public key blob, generated by the Microsoft Base Cryptographic Provider. This contains a key exchange public key.

0x00000000 06 02 00 00 00 a4 00 00  ........
0x00000008 52 53 41 31 00 02 00 00  RSA1....
0x00000010 01 00 01 00 e1 94 84 7a  .......z
0x00000018 27 4c 7b da db c5 99 dd  'L{.....
0x00000020 ed 20 1a b8 66 44 21 dc  . ..fD!.
0x00000028 10 e5 ee 48 62 39 ae 8f  ...Hb9..
0x00000030 cf 17 81 f0 37 8b b5 46  ....7..F
0x00000038 a9 65 b7 4e 75 83 84 4e  .e.Nu..N
0x00000040 4f ce f1 f2 ad a0 b1 22  O......"
0x00000048 09 ec c2 30 96 f8 27 2b  ...0..'+
0x00000050 33 cf a4 be              3...

Notice that the BLOBHEADER and RSAPUBKEY structures have been assigned the following values, and the last 64 bytes of the blob contain the public key's modulus data.

blobheader.bType    = PUBLICKEYBLOB;      // 0x06
blobheader.bVersion = CUR_BLOB_VERSION;   // 0x02
blobheader.Reserved = 0;                  // 0x0000
blobheader.aiKeyAlg = CALG_RSA_KEYX;      // 0x0000a400
rsapubkey.magic     = 0x31415352;         // "RSA1"
rsapubkey.bitlen    = 512;                // 0x00000200
rsapubkey.pubexp    = 65537;              // 0x00010001

When filling in the BLOBHEADER structure, your code should place zero in the Reserved field.


Private Key Blobs

Private key blobs (type PRIVATEKEYBLOB) are used to store RSA public/private key pairs. They have the following format:

BLOBHEADER blobheader;
RSAPUBKEY rsapubkey;
BYTE modulus[rsapubkey.bitlen/8];
BYTE prime1[rsapubkey.bitlen/16];
BYTE prime2[rsapubkey.bitlen/16];
BYTE exponent1[rsapubkey.bitlen/16];
BYTE exponent2[rsapubkey.bitlen/16];
BYTE coefficient[rsapubkey.bitlen/16];
BYTE privateExponent[rsapubkey.bitlen/8];

If the key blob is encrypted, then everything but the BLOBHEADER portion of the blob is encrypted. Note that the encryption algorithm and encryption key parameters are not stored along with the private key blob. It is the responsibility of the application to manage this information.

The following table describes each private key blob component. Note that these fields largely correspond to the ones described in section 7.2 of PKCS #1: RSA Encryption Standard.

Field | Description
blobheader | A BLOBHEADER structure as described in a previous section. The bType field must always have a value of PRIVATEKEYBLOB.
rsapubkey | A RSAPUBKEY structure as described in a previous section. The magic field must always have a value of 0x32415352 ("RSA2").
modulus | The modulus. This has a value of "prime1 * prime2" and is often known as "n".
prime1 | Prime number 1, often known as "p".
prime2 | Prime number 2, often known as "q".
exponent1 | Exponent 1. This has a numeric value of "d mod (p - 1)".
exponent2 | Exponent 2. This has a numeric value of "d mod (q - 1)".
coefficient | Coefficient. This has a numeric value of "(inverse of q) mod p".
privateExponent | Private exponent, often known as "d".


Sample Private Key Blob

The following hex dump shows a sample private key blob, generated by the Microsoft Base Cryptographic Provider. This contains a key exchange public/private key pair. Note that this sample contains a public key that is different than the one discussed in a previous section.

0x00000000  07 02 00 00 00 a4 00 00  ........
0x00000008  52 53 41 32 00 02 00 00  RSA2....
0x00000010  01 00 01 00 6b df 51 ef  ....k.Q.
0x00000018  db 6f 10 5c 32 bf 87 1c  .o.\2...
0x00000020  d1 4c 24 7e e7 2a 14 10  .L$~.*..
0x00000028  6d eb 2c d5 8c 0b 95 7b  m.,....{
0x00000030  c7 5d c6 87 12 ea a9 cd  .]......
0x00000038  57 7d 3e cb e9 6a 46 d0  W}>..jF.
0x00000040  e1 ae 2f 86 d9 50 f9 98  ../..P..
0x00000048  71 dd 39 fc 0e 60 a9 d3  q.9..`..
0x00000050  f2 38 bb 8d 5d 2c bc 1e  .8..],..
0x00000058  c3 38 fe 00 5e ca cf cd  .8..^...
0x00000060  b4 13 89 16 d2 07 bc 9b  ........
0x00000068  e1 20 31 0b 81 28 17 0c  . 1..(..
0x00000070  c7 73 94 ee 67 be 7b 78  .s..g.{x
0x00000078  4e c7 91 73 a8 34 5a 24  N..s.4Z$
0x00000080  9d 92 0d e8 91 61 24 dc  .....a$.
0x00000088  b5 eb df 71 66 dc e1 77  ...qf..w
0x00000090  d4 78 14 98 79 44 b0 19  .x..yD..
0x00000098  f6 f0 7d 63 cf 62 67 78  ..}c.bgx
0x000000a0  d0 7b 10 ae 6b db 40 b3  .{..k.@.
0x000000a8  b2 eb 2e 9f 31 34 2d cb  ....14-.
0x000000b0  bf a2 6a a6 1f e9 03 42  ..j....B
0x000000b8  f2 63 9b b7 33 d0 fe 20  .c..3..
0x000000c0  83 26 1f 56 a8 24 f5 6d  .&.V.$.m
0x000000c8  19 51 a5 92 31 e4 2b bc  .Q..1.+.
0x000000d0  11 c8 26 75 a0 51 e9 83  ..&u.Q..
0x000000d8  ca ee 4b f0 59 eb a4 81  ..K.Y...
0x000000e0  d6 1f 49 42 2b 75 89 a7  ..IB+u..
0x000000e8  9f 84 7f 1f c3 8f 70 b6  ......p.
0x000000f0  7e 06 5e 8b c9 53 65 80  ~.^..Se.
0x000000f8  b7 16 f2 5e 5e de 0b 57  ...^^..W
0x00000100  47 43 86 85 8a fb 37 ac  GC....7.
0x00000108  66 34 ba 09 1a b1 21 0b  f4....!.
0x00000110  aa fa 6c b7 75 a7 3e 23  ..l.u.>#
0x00000118  18 58 95 90 b5 29 a4 1e  .X...)..
0x00000120  15 76 52 56 bb 3d 6b 1d  .vRV.=k.
0x00000128  2a d1 9f 5c 8a c0 55 ea  *..\..U.
0x00000130  c3 29 a2 1e              .)..

Notice that the BLOBHEADER and RSAPUBKEY structures have been assigned the following values:

blobheader.bType    = PRIVATEKEYBLOB;     // 0x07
blobheader.bVersion = CUR_BLOB_VERSION;   // 0x02
blobheader.Reserved = 0;                  // 0x0000
blobheader.aiKeyAlg = CALG_RSA_KEYX;      // 0x0000a400
rsapubkey.magic     = 0x32415352;         // "RSA2"
rsapubkey.bitlen    = 512;                // 0x00000200
rsapubkey.pubexp    = 65537;              // 0x00010001

The following table shows the numeric values of each of the large numeric fields contained by the sample private key blob. As with all of the numbers in the public and private key blobs, these are in little endian byte order.

Field name Value
Modulus 6b df 51 ef db 6f 10 5c 32 bf 87 1c d1 4c 24 7e
e7 2a 14 10 6d eb 2c d5 8c 0b 95 7b c7 5d c6 87
12 ea a9 cd 57 7d 3e cb e9 6a 46 d0 e1 ae 2f 86
d9 50 f9 98 71 dd 39 fc 0e 60 a9 d3 f2 38 bb 8d
Prime #1 5d 2c bc 1e c3 38 fe 00 5e ca cf cd b4 13 89 16
d2 07 bc 9b e1 20 31 0b 81 28 17 0c c7 73 94 ee
Prime #2 67 be 7b 78 4e c7 91 73 a8 34 5a 24 9d 92 0d e8
91 61 24 dc b5 eb df 71 66 dc e1 77 d4 78 14 98
Exponent #1 79 44 b0 19 f6 f0 7d 63 cf 62 67 78 d0 7b 10 ae
6b db 40 b3 b2 eb 2e 9f 31 34 2d cb bf a2 6a a6
Exponent #2 1f e9 03 42 f2 63 9b b7 33 d0 fe 20 83 26 1f 56
a8 24 f5 6d 19 51 a5 92 31 e4 2b bc 11 c8 26 75
Coefficient a0 51 e9 83 ca ee 4b f0 59 eb a4 81 d6 1f 49 42
2b 75 89 a7 9f 84 7f 1f c3 8f 70 b6 7e 06 5e 8b
Private Exponent c9 53 65 80 b7 16 f2 5e 5e de 0b 57 47 43 86 85
8a fb 37 ac 66 34 ba 09 1a b1 21 0b aa fa 6c b7
75 a7 3e 23 18 58 95 90 b5 29 a4 1e 15 76 52 56
bb 3d 6b 1d 2a d1 9f 5c 8a c0 55 ea c3 29 a2 1e


Simple Key Blobs

Simple key blobs (type SIMPLEBLOB) are used to store and transport session keys. These are always encrypted with a key exchange public key. They have the following format:

BLOBHEADER blobheader;
ALG_ID algid;
BYTE encryptedkey[rsapubkey.bitlen/8];

The algorithm identifier that immediately follows the BLOBHEADER structure specifies the encryption algorithm that was used to encrypt the session key data. This typically has a value of CALG_RSA_KEYX, indicating that the session key data was encrypted with a key exchange public key, using the RSA Public-Key algorithm.

The encrypted session key data is in the form of a PKCS #1, type 2 encryption block. For details on this data format, see The Public-Key Cryptography Standards (PKCS), published by RSA Data Security, Inc.

This data is always the same size as the public key's modulus. For example, public keys generated by the Microsoft Base Cryptographic Provider are always 512 bits (64 bytes) in length, so the encrypted session key data is also always 64 bytes.


Building a Simple Key Blob (SIMPLEBLOB)

Two data items are required before a SIMPLEBLOB data structure can be built: the session key that is to be transported and the public key to be used to encrypt it. This example uses a 40-bit RC4 session key and the public key from the previous section. The actual value of the session key material is:

0x00000000 74 4f 06 35 3f           tO.5?

The first step is building the PKCS #1, type 2 encryption block. This is always the same size as the public key's modulus (64 bytes) and contains the following fields:

Bytes | Description
5 | Session key material. The size of this field will vary, depending on the size of the session key. As you can see from comparing the hex dump of the session key earlier in this chapter and the hex dump of the encryption block later in this section, the bytes in the session key data are reversed before they are placed in the encryption block. This is because Windows NT formats data in little endian format, and the encryption block must be built in big endian format.
1 | Zero value.
56 | Random padding data. The size of this field is adjusted as necessary so that the encryption block's overall length is correct. None of these bytes are allowed to be zero.
1 | The PKCS block type (0x02).
1 | Zero value.

You may notice that the order of this table is reversed from the diagram found in the PKCS documentation. This is because we are building the encryption block in big endian on a little endian computer.

After the encryption block has been built, it looks something like this:

0x00000000 3f 35 06 4f 74 00 c9 db  ?5.Ot...
0x00000008 b1 74 b0 de 8e d4 aa c5  .t......
0x00000010 99 8a 4d 19 4f 0f ed 24  ..M.O..$
0x00000018 b0 2e 93 fe e9 f4 d4 93  ........
0x00000020 dc ac 9e 9f 3a 62 be f1  ....:b..
0x00000028 e4 1d 44 5c 33 e5 2f 4f  ..D\3./O
0x00000030 58 01 95 16 36 f7 86 65  X...6..e
0x00000038 68 6c 2a 28 79 55 02 00  hl*(yU..

The next step is to encrypt the block with the appropriate public key. After this is done, the encryption block looks like gibberish:

0x00000000 e3 c1 78 62 c4 1f 51 4f  ..xb..QO
0x00000008 e9 50 89 fd 0d 58 bd 9d  .P...X..
0x00000010 74 c7 54 19 bd 97 3b a0  t.T...;.
0x00000018 f0 6c ee 86 05 74 16 62  .l...t.b
0x00000020 27 a5 99 63 c4 6f 95 ed  '..c.o..
0x00000028 3e 93 ba 9a ea 36 cc 96  >....6..
0x00000030 92 e8 aa 15 2c 50 a1 3c  ....,P.<
0x00000038 d3 1f 08 e2 82 cd 90 2b  .......+

Finally, the BLOBHEADER structure and the algorithm identifier are tacked onto the front of the encryption block, resulting in a complete SIMPLEBLOB data structure:

0x00000000 01 02 00 00 01 68 00 00  .....h..
0x00000008 00 a4 00 00 e3 c1 78 62  ......xb
0x00000010 c4 1f 51 4f e9 50 89 fd  ..QO.P..
0x00000018 0d 58 bd 9d 74 c7 54 19  .X..t.T.
0x00000020 bd 97 3b a0 f0 6c ee 86  ..;..l..
0x00000028 05 74 16 62 27 a5 99 63  .t.b'..c
0x00000030 c4 6f 95 ed 3e 93 ba 9a  .o..>...
0x00000038 ea 36 cc 96 92 e8 aa 15  .6......
0x00000040 2c 50 a1 3c d3 1f 08 e2  ,P.<....
0x00000048 82 cd 90 2b              ...+

Notice that the BLOBHEADER structure and the algorithm identifier have been assigned the following values:

blobheader.bType    = SIMPLEBLOB;         // 0x01
blobheader.bVersion = CUR_BLOB_VERSION;   // 0x02
blobheader.Reserved = 0;                  // 0x0000
blobheader.aiKeyAlg = CALG_RC4;           // 0x00006801
algid               = CALG_RSA_KEYX;      // 0x0000a400

When filling in the BLOBHEADER structure, your code should place zero in the Reserved field.


Deriving Session Keys

Applications derive session keys from hash values by using the CryptDeriveKey function. The underlying mechanism is very simple. The first few bytes of the hash value (however many are required) are used as the session key material. If the CRYPT_CREATE_SALT flag is specified, then the next few bytes are used as the salt value. The remaining bytes of the hash value are not used.

For example, if you have an SHA hash value (160 bits) and want to create a 40-bit session key (with 88 bits of salt) from it, the first five bytes would be used as the session key material and the next 11 bytes would be used as the salt. The last 4 bytes would be unused.

Note that hash values and session keys are considered here to be blocks of data, not large integers. Byte ordering (big endian versus little endian) is thus not relevant.


Key Derivation Sample

This data was generated using the Microsoft Base Cryptographic Provider. Your session key length and salt length may be different, but the basic process should be the same.

Assume that an application has a password ("1134-kelp") that it wants to derive a session key from. It would first hash the password with the CryptHashData function, in this case specifying the MD5 hash algorithm. The following hash value is generated and held internal to the CSP:

0x00000000 73 40 e6 e2 74 b8 ea 39  s@..t..9
0x00000008 93 95 aa 29 d6 38 b5 2a  ...).8.*

The application would then call the CryptDeriveKey function in order to create a session key, in this case an RC4 stream cipher key. The CSP uses the first five bytes of the previous hash value as the key itself:

0x00000000 73 40 e6 e2 74           s@..t

Because the CRYPT_CREATE_SALT flag was not specified, the key is given a salt value of zero.

If the session key is used to encrypt the following plaintext buffer:

0x00000000 00 01 02 03 04 05 06 07  ........
0x00000008 08 09 0a 0b 0c 0d 0e 0f  ........
0x00000010 10 11 12 13 14 15 16 17  ........
0x00000018 18 19 1a 1b 1c 1d 1e 1f  ........

The following ciphertext data is generated:

0x00000000 26 59 de 24 44 fa 36 9c  &Y.$D.6.
0x00000008 11 0c bb 9d b6 a2 bd 24  .......$
0x00000010 04 2e e3 ba 72 76 f3 27  ....rv.'
0x00000018 8d d5 b4 2f 56 cf f8 c9  .../V...

If the application does specify the CRYPT_CREATE_SALT flag during the CryptDeriveKey function call, then the key is given the following 11-byte salt value:

0x00000000 b8 ea 39 93 95 aa 29 d6  ..9...).
0x00000008 38 b5 2a                 8.*

In this case, the following ciphertext data is generated when the previous plaintext buffer is encrypted:

0x00000000 47 f4 5d e2 cc 3b 87 1b  G.]..;..
0x00000008 95 bc fc 39 fb 86 d3 05  ...9....
0x00000010 da a2 91 fb 80 f1 2a 22  ......*"
0x00000018 c3 b9 ec 91 dd 9f af 50  .......P


Hashing Session Keys

When an application uses the CryptHashSessionKey function to hash a session key, only the base key material should be hashed. For a 40-bit key, this will be 5 bytes of data.

The key should be hashed in big endian byte order. For example, if the Base Cryptographic Cryptographic Provider were used to create and hash a session key that had a value of "4a 3a ee 77 37", then the bytes would need to be reversed before the hashing operation is performed. In this example, the following hash values would be produced:

MD5: 0b 15 55 0a a0 03 f9 3f 75 82 f7 e7 91 32 bc 8c
SHA: 3c 37 72 93 53 ff 2a 4f ef 12 54 18 5b 3a c4 63 03 fd 07 5d


Digital Signature Mechanics

Applications sign or verify hash values by using the CryptSignHash and CryptVerifySignature functions. The application often specifies a description string, which must added to the hash object before it is signed or verified.

The signature process typically goes something like this:

  1. The application creates a hash object by using CryptCreateHash.
  2. The application adds data to the hash object by using CryptHashData, CryptHashSessionKey, or both.
  3. The application calls the CryptSignHash function to sign the hash value, specifying a description string.
  4. The operating system layer accepts the CryptSignHash invocation, converts the description string to Unicode (if it isn't Unicode already), and then hands off the task to the CSP via the CPSignHash function.
  5. The CSP adds the Unicode description string to the hash object, via the CPHashData function. The terminating null character is not hashed in.
  6. The CSP completes the hash and obtains the hash value to be signed by using the CPGetHashParam function.
  7. The CSP takes the hash value, pads it out to the size of the public key modulus, and encrypts it by using the signature private key.

    The padding around the hash value must be in the format specified by the Public-Key Cryptography Standards (PKCS), available from RSA Data Security. The hash algorithm used must be encoded as described in PKCS #1, Section 6.3.

  8. The signature block is then returned to the application, via the operating system layer.


Signature Sample

This section steps through the signature process. This sample starts with the hash value used in the previous sample; that is, an MD5 hash of the "1134-kelp" string. This hash value is as follows:

0x00000000 73 40 e6 e2 74 b8 ea 39  s@..t..9
0x00000008 93 95 aa 29 d6 38 b5 2a  ...).8.*

This example assumes that the application specified "Test Signature" as the description string. The first thing that the CSP does is to add this string to the hash object that is being signed. Of course, the description string is received by the CSP in Unicode format, as follows:

0x00000000 54 00 65 00 73 00 74 00  T.e.s.t.
0x00000008 20 00 53 00 69 00 67 00   .S.i.g.
0x00000010 6e 00 61 00 74 00 75 00  n.a.t.u.
0x00000018 72 00 65 00              r.e.

After the description string has been hashed in, the hash value is extracted:

0x00000000 a8 2b df c2 c9 f1 bb 62  .+.....b
0x00000008 38 78 d4 60 fa ce 5c 2a  8x.`..\*

The next step is building a PKCS signature block. This is always the same size as the public key's modulus (64 bytes) and contains the following fields:

Bytes | Description
16 | Hash of data to be signed. The size of this field will vary, depending on the hash algorithm used. As you can see from comparing the hex dump of the hash value earlier in this chapter and the hex dump of the following encryption block, the bytes in the hash value are reversed before they are placed in the encryption block. This is because Windows NT formats data in little endian format, and the encryption block must be built in big endian format.
18 | ASN.1 encoded hash algorithm specifier. The size of this field will vary, depending on the hash algorithm used. Note that this data is also reversed. A description of ASN.1 is beyond the scope of this document, but a table of common ASN.1 strings is provided in the next section. For more information on ASN.1, see the PKCS documentation.
1 | Zero value.
27 | Padding data (0xff's). The size of this field is adjusted as necessary so that the signature block's overall length is correct.
1 | The PKCS block type (0x01).
1 | Zero value.

You may notice that the order of this table is reversed from the diagram found in the PKCS documentation. This is because the signature block is built in big endian on a little endian computer.

Once the signature block has been built, it looks something like this:

0x00000000 2a 5c ce fa 60 d4 78 38  *\..`.x8
0x00000008 62 bb f1 c9 c2 df 2b a8  b.....+.
0x00000010 10 04 00 05 05 02 0d f7  ........
0x00000018 86 48 86 2a 08 06 0c 30  .H.*...0
0x00000020 20 30 00 ff ff ff ff ff   0......
0x00000028 ff ff ff ff ff ff ff ff  ........
0x00000030 ff ff ff ff ff ff ff ff  ........
0x00000038 ff ff ff ff ff ff 01 00  ........

The next step is to encrypt the block with the appropriate private key. In this example, the private key used is the one corresponding to the public key used in the previous section "Public Key Blobs." This results in a completed digital signature:

0x00000000 64 f6 46 3a 97 2e 83 38  d.F:...8
0x00000008 09 57 43 cb ca 41 59 0d  .WC..AY.
0x00000010 03 35 d6 e4 36 6f 2c fc  .5..6o,.
0x00000018 63 43 95 c4 fd e2 c4 ed  cC......
0x00000020 06 da 9a 21 98 fc 0a 6e  ...!...n
0x00000028 3f 1c ad 3a db 7c 83 2f  ?..:.|./
0x00000030 14 d0 58 80 02 df dc 96  ..X.....
0x00000038 70 09 00 e3 5b bd 2b 45  p...[.+E


PKCS Hash Algorithm Encodings

All RSA digital signature blocks contain an ASN.1 encoded hash algorithm identification string. This is mentioned in the previous section. The following table lists the encodings for the algorithms supported by the Microsoft Base Cryptographic Provider, as well as by most other RSA CSPs.

Algorithm Encoding
MD2 0x00000000 10 04 00 05 02 02 0d f7 ........
0x00000008 86 48 86 2a 08 06 0c 30 .H.*...0
0x00000010 20 30 0
MD4 0x00000000 10 04 00 05 04 02 0d f7 ........
0x00000008 86 48 86 2a 08 06 0c 30 .H.*...0
0x00000010 20 30 0
MD5 0x00000000 10 04 00 05 05 02 0d f7 ........
0x00000008 86 48 86 2a 08 06 0c 30 .H.*...0
0x00000010 20 30 0
SHA 0x00000000 14 04 00 05 1a 02 03 0e ........
0x00000008 2b 05 06 09 30 21 30 +...0!0

The encoded OID strings shown in the previous table include "wrapper" bytes. For example, the encoded string shown for SHA contains the following information (for clarity, the bytes are reverse ordered):


RSA/Full CSP Reference Overview

This reference contains detailed information about all of the Microsoft® RSA/Full Cryptographic Service Provider (CSP) functions.

This information is divided into the following sections:

  • Service Provider Functions

    Covers connecting to (and disconnecting from) CSPs and customizing their operation.

  • Key Generation and Exchange Functions

    Covers creating, configuring, and destroying cryptographic keys, as well as exchanging them with other users

  • Data Encryption Functions

    Covers encryption and decryption operations

  • Hashing and Digital Signature Functions

    Covers the computation of hashes (also known as message digests), as well as the creation and verification of digital signatures


Service Provider Functions

The functions described in this chapter are used by applications to connect to (and disconnect from) cryptographic service providers (CSPs). The following table briefly describes each function.

Function | Description
CPAcquireContext | Acquires a handle to a particular key container within the CSP.
CPGetProvParam | Retrieves attributes of the CSP.
CPReleaseContext | Releases the handle acquired by CPAcquireContext.
CPSetProvParam | Specifies attributes of the CSP.


CPAcquireContext

The CPAcquireContext function is used to acquire a handle to the key container specified by the pszContainer parameter.

BOOL CPAcquireContext(
  HCRYPTPROV *phProv,       // out
  CHAR *pszContainer,       // in, out
  DWORD dwFlags,            // in
  PVTableProvStruc pVTable  // in
);

Parameters

phProv
Address to which the function copies a handle to the CSP.
pszContainer
Key container name. This is a zero-terminated string, of typically no more than MAX_PATH characters, including the terminator. pszContainer is to be set to NULL when dwFlags is set to CRYPT_VERIFYCONTEXT.

If this parameter is NULL, then a default key container name will be used. For example, the Microsoft® RSA Base Provider uses the logon name of the user currently logged on as the key container name in this situation.

dwFlags

Flag values. This parameter is normally zero, but the following flags are allowed:

CRYPT_VERIFYCONTEXT
If this flag is set, then the application will have no access to the private keys and the pszContainer parameter must be set to NULL.

This option is intended to be used with applications that will not be using private keys.

When CryptAcquireContext (in the CryptoAPI) is called, many CSPs will require input from the owning user before granting access to the private keys in the key container. For example, the private keys may be encrypted, requiring a password from the user before they can be used. However, if the CRYPT_VERIFYCONTEXT flag is specified, access to the private keys is not required and the user interface can be bypassed.

CRYPT_NEWKEYSET
If this flag is set, then a new key container will be created with the name specified by pszContainer. If pszContainer is NULL, then a key container with the default name will be created.

The CSP is not required to create any key pairs at this point. Instead, the key pairs are typically generated later via the CPGenKey function. However, the CSP may generate key pairs during the CPAcquireContext function call at the CSP author's discretion.

CRYPT_MACHINE_KEYSET
By default keys are stored in the HKEY_CURRENT_USER portion of the registry. The CRYPT_MACHINE_KEYSET flag may be used when calling CryptAcquireContext (in the CryptoAPI) with the CRYPT_NEW_KEYSET or CRYPT_DELETE_KEYSET flag and, in this case, the keys will be stored in the HKEY_LOCAL_MACHINE portion of the registry.

Note that CRYPT MACHINE KEYSET applies specifically to the Microsoft Provider Types. Other provider types may store keys differently and should ignore this flag.

For CSPs to be compatible with the Microsoft Cryptograpic Providers, they should implement the CRYPT MACHINE KEYSET flag. In the case of many CSPs, this may mean just ignoring this flag. This flag is used for keys that are machine keys, which means these keys need to be accessible to applications that are not associated with a user account. It is generally not good practice to have a UI associated with these keys because these keys could easily be used by an unattended server application. Microsoft Providers store keys in the registry and the machine keys are stored in the HKEY_LOCAL_MACHINE portion of the registry. In addition, with the Microsoft Providers, ACLs may be set on these keys by using CPGetProvParam and CPSetProvParam with the PP_KEYSET_SEC_DESCR value. CSP writers may want to consider allowing the setting of Microsoft Windows NT® ACLs on keys as well.

Note When key containers are created, most CSPs will not automatically create any public/private key pairs. These keys must be created as a separate step by using the CryptGenKey function (in the CryptoAPI).

CRYPT_DELETEKEYSET.
If this flag is set, then the key container specified by pszContainer is deleted. If pszContainer is NULL, then the key container with the default name is deleted. All key pairs in the key container are also destroyed.

When the CRYPT_DELETEKEYSET flag is set, the value returned in phProv is undefined and, thus, the CryptReleaseContext function (in the CryptoAPI) need not be called afterwards.

pVTable
Pointer to a VTableProvStruct structure that contains a list of functions provided by the operating system for use by the CSP.

This is discussed further in the Remarks section.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The dwFlags parameter has an illegal value.
NTE_BAD_KEYSET | The key container could not be opened, and may not exist.
NTE_BAD_KEYSET_PARAM | The pszContainer parameter is set to an illegal value.
NTE_BAD_SIGNATURE | The digital signature of an auxiliary DLL did not verify correctly. Either the DLL or the digital signature has been tampered with.
NTE_EXISTS | The dwFlags parameter is CRYPT_NEWKEYSET, but the key container already exists.
NTE_KEYSET_ENTRY_BAD | The registry entry for the pszContainer key container was found but is corrupt
NTE_KEYSET_NOT_DEF | The key container specified by pszContainer does not exist.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.
NTE_PROVIDER_DLL_FAIL | An auxiliary DLL file could not be loaded, and may not exist. If it exists, the file is not a valid DLL.

Remarks

The VTableProvStruc structure and the function pointers that it contains are defined as:

typedef struct _VTableProvStruc {
    DWORD   Version;
    FARPROC FuncVerifyImage;
    FARPROC FuncReturnhWnd;
    DWORD   dwProvType;
    BYTE *pbContextInfo;
    DWORD cbContextInfo;
} VTableProvStruc, *PVTableProvStruc;
BOOL FuncVerifyImage(LPCSTR lpszImage, BYTE *pSigData);
BOOL FuncReturnhWnd(DWORD *phWnd);

The Version field is currently always set to 2. The value of this field will be incremented as additional function pointers are added to the structure, or as other changes are made.

All auxiliary DLLs that your CSP makes function calls into must be signed, in the same manner (and with the same key) as is the primary CSP DLL. To make this work properly, the auxiliary DLLs must be loaded dynamically, via the LoadLib function. But before the LoadLib function is called, the signature of the DLL must be verified. The CSP does this verification by calling the FuncVerifyImage function, as illustrated in the following code fragment.

BOOL (FARPROC *ProvVerifyImage)(LPCSTR lpszImage, BYTE *pSigData);
BYTE bSignature[72];

// "ProvVerifyImage" has been set to "pVTable->FuncVerifyImage"
// within the CPAcquireContext function.

// Load the c:\winnt40\system32\winfoo.sig file into the
// bSignature buffer. During development, this file is created
// with the sign.exe utility.
...

// Verify the signature on the c:\winnt40\system32\winfoo.dll file.
if(RCRYPT_FAILED(ProvVerifyImage("c:\\winnt40\\system32\\winfoo.dll",
                                 bSignature)) {
    SetLastError(NTE_BAD_SIGNATURE);
    return CRYPT_FAILED;
}

// Load the DLL with the LoadLib function, then acquire pointers to
// the member functions with the GetProcAddress function.
...

The FuncReturnWnd entry in the VTableProvStruc structure can be called by CSPs to retrieve a window handle that it is to use when interacting directly with the user via Microsoft Win32®. CSPs that do not communicate directly with the user (and ones that use dedicated hardware for this purpose) can ignore this entry. This window handle is zero by default, but some applications will set it to a different value by using the CryptSetProvParam function (in the CryptoAPI).

The dwProvType field specifies the type of provider to acquire. The following provider types are predefined, and are discussed in detail in Interoperability with RSA CSPs.

  • PROV_RSA_FULL
  • PROV_RSA_SIG
  • PROV_DSS
  • PROV_FORTEZZA
  • PROV_MS_EXCHANGE

The pbContextInfo and cbContextInfo fields specifiy the information set when performing a CPSetProvParam with the PP_CONTEXT_INFO parameter number specified.

See Also

CPReleaseContext, CryptAcquireContext, CryptSetProvParam


CPGetProvParam

The CPGetProvParam function is called by applications to retrieve various data about the CSP.

BOOL CPGetProvParam(
  HCRYPTPROV hProv,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // out
  DWORD *pdwDataLen, // in, out
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
dwParam
Parameter number. See the "Remarks" section for the list of currently defined parameters.
pbData
Parameter data buffer. The function copies the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

If this parameter is NULL, then no parameter data should be copied. Instead, the required buffer size (in bytes) should be returned in pdwDataLen. This is not an error.

As noted in CryptGetProvParam (in the CryptoAPI), when one of the enumeration parameters is being read, the value returned in pdwDataLen should be the size of the largest item in the enumeration list.

pdwDataLen
Address of the parameter data length. Upon function entry, this contains the number of bytes in the pbData buffer. Upon exit, this must be set to the number of bytes of parameter data copied to the pbData buffer.

If the buffer specified by pbData is not large enough to hold the requested data, the ERROR_MORE_DATA error code should be returned via the SetLastError function. In this case, the required buffer size must be returned in pdwDataLen.

If this function fails with any error code other than ERROR_MORE_DATA, zero should be returned in this parameter.

dwFlags
Flag values. Currently, the following flag has been defined for this function:
CRYPT_FIRST
When an enumeration parameter is being read (for example, PP_ENUMALGS or PP_ENUMCONTAINERS) and this flag is set, the first item in the enumeration list is to be returned. Otherwise, the next item in the list is returned.

If this flag is set when a non-enumeration parameter is being read, the NTE_BAD_FLAGS error code should be returned.

Note The following flag values are specific to RSAbase use only. CSPs that use a hardware solution will not use these flags.

CRYPT_MACHINE_KEYSET
When the enumeration parameter PP_ENUMCONTAINERS is being read, then the CRYPT_MACHINE_KEYSET flag can be specified. This flag can be set if you want the enumeration to come from the HKEY_LOCAL_MACHINE portion of the registry rather than from the HKEY_CURRENT_USER portion of the registry (the default).
SECURITY_INFORMATION bit flags
When the dwParam is PP_KEYSET_SEC_DESCR, the security descriptor on the registry key where the keys are stored is being retrieved. For this case, dwFlags is used to pass in the SECURITY_INFORMATION bit flags (can be combined with a bitwise OR operation) that indicates the requested security information. For more information, search the Microsoft Platform SDK for SECURITY_INFORMATION. The following is specified there:
typedef DWORD SECURITY_INFORMATION;
Value | Meaning
OWNER_SECURITY_INFORMATION | Indicates the owner identifier of the object is being referenced.
GROUP_SECURITY_INFORMATION | Indicates the primary group identifier of the object is being referenced.
DACL_SECURITY_INFORMATION | Indicates the discretionary ACL of the object is being referenced.
SACL_SECURITY_INFORMATION | Indicates the system ACL of the object is being referenced.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_MORE_DATA | The pbData buffer is not large enough to hold the requested data.
ERROR_NO_MORE_ITEMS | The end of the enumeration list has been reached. No valid data has been placed in the pbData buffer. This error is returned only when dwParam equals PP_ENUMALGS or PP_ENUMCONTAINERS.
NTE_BAD_FLAGS | The value of the dwFlags parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The context specified by hProv is invalid.

Remarks

The dwParam parameter can be set to one of the following values:

PP_CONTAINER
The key container name. A zero-terminated CHAR string containing the name of the current key container should be placed in the pbData buffer. The length of the string (including the terminating zero) should be returned in pdwDataLen.

Applications will often use this string to acquire this key container in a subsequent session, by passing it into the pszContainer parameter of CryptAcquireContext (in the CryptoAPI).

If the CSP only supports one key container (for example, one based on a smartcard with limited memory), then key container names may not be used. If this is the case, a null string "\0" can be returned in the pbData buffer.

PP_ENUMALGS
Supported algorithms. See CryptGetProvParam (in the CryptoAPI) for a description of this parameter.
PP_ENUMCONTAINERS
Key container names. A zero-terminated CHAR string containing the name of one of the key containers maintained by the CSP should be placed in the pbData buffer.

Applications read this parameter repeatedly in order to enumerate all of the key containers maintained by the CSP, in a manner similar to the PP_ENUMALGS parameter.

If the CSP supports only one key container, this parameter is often not supported. In this case, an NTE_BAD_TYPE error code should be returned.

PP_IMPTYPE
The CSP implementation type. A DWORD value containing the CSP's implementation type should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.

The following implementation types are currently defined (in Wincrypt.h):

  • CRYPT_IMPL_HARDWARE
  • CRYPT_IMPL_SOFTWARE
  • CRYPT_IMPL_MIXED
  • CRYPT_IMPL_UNKNOWN
PP_NAME
The CSP name. A zero-terminated CHAR string containing the name of the CSP should be placed in the pbData buffer, and the length of the string (including the terminating zero) placed in pdwDataLen. This string must exactly match the "CSP Name" entries that the CSP's setup program installs in the Windows® Registry.

Applications will often use this CSP name in order to connect to the CSP in a subsequent session, by passing the name for the pszProvider parameter of CryptAcquireContext (in the CryptoAPI).

Note Since it is desirable to perpetuate the CSP name across versions for backward compatibility, you may want to use only general terms in the CSP name and avoid specifics such as version numbers.

PP_VERSION
The CSP version number. A DWORD value containing the version number of the CSP should be placed in the pbData buffer, and a value of 4 should be placed in pdwDataLen. The least significant byte should contain the minor version number and the next most significant byte the major version number. For example, version 1.0 would be represented here as 0x00000100.
PP_KEYSET_SEC_DESCR.
Indicates that the security descriptor is to be retrieved for the registry entry where the key set is stored.

Note The PP_KEYSET_SEC_DESCR flag is not supported under Microsoft Windows 95.

The dwFlags parameter is used to pass in the SECURITY_INFORMATION bit flags that indicate the requested security information. The pointer to the security descriptor is returned in the pbData parameter and the length of the security descriptor is returned in the pcbData parameter. It may be helpful to look at the documentation on RegGetKeySecurity and RegSetKeySecurity (WIN32 calls).

In the Win32 SDK in MSTOOLS\samples\win32\winnt\security\secperf is sample code showing how to manipulate NT ACLs.

Algorithm Identifiers

When enumerating algorithms (dwParam == PP_ENUMALGS), your application may need to determine the class of a particular algorithm. For example, you may want to display a list of encryption algorithms to the user and disregard the rest. This can be done with the GET_ALG_CLASS(x) macro. This macro takes an algorithm identifier as an argument and returns a code indicating the general class of algorithm that the identifier belongs to. Possible return values include:

ALG_CLASS_DATA_ENCRYPT

ALG_CLASS_HASH

ALG_CLASS_KEY_EXCHANGE

ALG_CLASS_SIGNATURE

The following table lists the algorithms supported by the Microsoft RSA Base Provider along with the class of each algorithm.

Name Identifier Class

"MD2" CALG_MD2 ALG_CLASS_HASH

"MD5" CALG_MD5 ALG_CLASS_HASH

"SHA" CALG_SHA ALG_CLASS_HASH

"MAC" CALG_MAC ALG_CLASS_HASH

"RSA_SIGN" CALG_RSA_SIGN ALG_CLASS_SIGNATURE

"RSA_KEYX" CALG_RSA_KEYX ALG_CLASS_KEY_EXCHANGE

"RC2" CALG_RC2 ALG_CLASS_DATA_ENCRYPT

"RC4" CALG_RC4 ALG_CLASS_DATA_ENCRYPT

If your application does not recognize an algorithm identifier, it is not recommended that you use the algorithm. Making use of an unknown cryptographic algorithm can sometimes produce unpredictable results.

See Also

CPAcquireContext, CPSetProvParam, CryptGetProvParam


CPReleaseContext

The CPReleaseContext function is used to release a context created by CPAcquireContext.

BOOL CPReleaseContext(
  HCRYPTPROV hProv,  // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The value of the dwFlags parameter is invalid.
NTE_BAD_UID | The context specified by hProv is invalid.

Remarks

After this function has been called, the hProv handle becomes invalid. All session keys and hash objects that have previously been created by using the hProv handle can be destroyed at this time. Ideally, the application has already done this via CryptDestroyKey and CryptDestroyHash (both in the CryptoAPI), but your CSP shouldn't depend on it.

See Also

CPAcquireContext, CryptReleaseContext


CPSetProvParam

The CPSetProvParam function allows applications to customize the operations of a CSP.

BOOL CPSetProvParam(
  HCRYPTPROV hProv,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
dwParam
The parameter number to set. The currently defined parameter values are as follows (see "Remarks" for additional details).
PP_KEYSET_SEC_DESCR
Specifies that the security descriptor on the registry entry where the stored key set is being assigned, and its value is contained in pbData. See secperf.c in the Microsoft Platform SDK which shows how to manipulate Microsoft Windows NT ACLs
pbData
Parameter data buffer. Upon entry to the function, this buffer will contain the data that corresponds to the dwParam parameter number. The form of this data will vary, depending on the parameter number.
dwFlags
The flag values. When dwParam is PP_KEYSET_SEC_DESCR, dwFlags contains the SECURITY_INFORMATION applicable bit flags (can be combined with a bitwise OR operation. See CryptGetProvParam (in the CryptoAPI) for additional details.

Note The PP_KEYSET_SEC_DESCR flag is not supported under Microsoft Windows 95.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The value of the dwFlags parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The context specified by hProv is invalid.
NTE_FAIL | The function failed in some unexpected way.

Remarks

It is expected that CSP authors will define parameters for this function as necessary. If these are general-purpose in nature, rather than applying to a single provider type, they should be defined in coordination with Microsoft. This will promote cross-vendor standardization, and allow the new parameter numbers to be added to the standard Win32 header files.

Note Some applications will call the CryptSetProvParam function (in the CryptoAPI) with the dwParam parameter set to PP_CLIENT_HWND, in order to specify the window handle that the CSP is to use when interacting with the user. In this case, the application passes in the window handle as a DWORD in the pbData buffer. Applications will typically make this CryptSetProvParam function call before calling CryptAcquireContext (in the CryptoAPI). Because of this, the CryptSetProvParam function is not passed down to the CSP when the parameter is PP_CLIENT_HWND. The CSP obtains this window handle via a virtual function pointer obtained from the CPAcquireContext function call.

See Also

CPAcquireContext, CPGetProvParam, CryptSetProvParam


Key Generation and Exchange Functions

The functions described in this chapter are used by applications to create, configure, and destroy cryptographic keys, as well as to exchange them with other users. The following table briefly describes each function.

Function | Description
CPDeriveKey | Creates a key derived from a password.
CPDestroyKey | Destroys a key.
CPDuplicateKey | Makes an exact copy of a key and the state the key is in.
CPExportKey | Transfers a key from the CSP into a key blob in the application's memory space.
CPGenKey | Creates a random key.
CPGenRandom | Generates random data.
CPGetKeyParam | Retrieves a key's parameters.
CPGetUserKey | Gets a handle to the key exchange or signature key.
CPImportKey | Transfers a key from a key blob to a CSP.
CPSetKeyParam | Specifies a key's parameters.


CPDeriveKey

The CPDeriveKey function generates cryptographic session keys derived from base data. This function guarantees that all keys generated from the same base data will be identical, provided that the same algorithms are specified. The base data can be a password or any other user data.

BOOL CPDeriveKey(
  HCRYPTPROV hProv,      // in
  ALG_ID Algid,          // in
  HCRYPTHASH hBaseData,  // in
  DWORD dwFlags,         // in
  HCRYPTKEY *phKey       // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
Algid
Identifier for the encryption algorithm for which the key is to be generated. This algorithm must be one of those supported by this CSP.
See CPGenKey.
hBaseData
Handle to a hash object that has been fed exactly the base data.
dwFlags
Flags specifying attributes pertaining to the session key generated. Not all CSPs will support all flags. The flags currently defined are:
CRYPT_EXPORTABLE
If this flag is set, then the session key can be transferred out of the CSP into a key blob through the CPExportKey function. Because keys generally must be exportable, this flag should usually be set.

If this flag is not set, then the session key will not be exportable. This means the key will be available only within the current session and only the application that created it will be able to use it.

This flag does not apply to public/private key pairs.

CRYPT_CREATE_SALT
Typically, when a session key is made from a hash value, there are a number of leftover bits. For example, if the hash value is 128 bits and the session key is 40 bits, there will be 88 bits left over.

If this flag is set, then the key will be assigned a salt value based on the unused hash value bits. You can retrieve this salt value by using the CPGetKeyParam function with the dwParam parameter set to KP_SALT.

If this flag is not set, then the key will be given a salt value of zero.

When keys with nonzero salt values are exported (by using CPExportKey), the salt value must also be obtained and kept with the key blob.

CRYPT_NO_SALT
Specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft® Cryptographic Providers--Release Notes.
CRYPT_USER_PROTECTED
If this flag is set, then the user will be notified through a dialog box or another method when this key is used to attempt certain actions. The precise behavior is specified by the CSP being used. Prior to Microsoft Internet Explorer 4.0, the Microsoft Cryptographic Providers ignore this flag. Starting with Microsoft Internet Explorer 4.0, Microsoft Cryptographic Providers support this flag value.
CRYPT_UPDATE_KEY
Some CSPs use session keys that are derived from multiple hash values. When this is the case, CPDeriveKey must be called multiple times.

If this flag is set, a new session key is not generated. Instead, the key specified by phKey is modified. The precise behavior of this flag is dependent on the type of key being generated and on the particular CSP being used.

The Microsoft Cryptographic Providers ignore this flag.

phKey
Address to which the function copies the handle of the newly generated 85 key.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_HASH | The hBaseData parameter does not contain a valid handle to a hash object.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_FAIL | The function failed in some unexpected way.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.

Remarks

If CSP interoperability is important to you, then your session keys must be derived in the precise manner specified by the CSP's type. For example, if your CSP's type is PROV_RSA_FULL or PROV_RSA_SIG, then see Interoperability with RSA CSPs for information on how the key derivation must be performed.

Of course, if you are defining your own CSP type, then you are free to derive session keys in any manner that you see fit.

See Also

CPDestroyKey, CPGenKey, CryptDeriveKey


CPDestroyKey

The CPDestroyKey function releases the handle referenced by the hKey parameter. After a key handle has been released, it becomes invalid and cannot be used again.

BOOL CPDestroyKey(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey     // in
):

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the key to be destroyed.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a key.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.

Remarks

If the handle refers to a session key, or to a public key that has been imported into the CSP via CryptImportKey, this function destroys the key and frees the memory that the key occupied. The CSP will typically scrub the memory where the key was held before freeing it.

On the other hand, if the handle refers to a public/private key pair (obtained from CryptGetUserKey), the underlying key pair is not destroyed by this function. Only the handle is destroyed.

See Also

CPDeriveKey, CPGenKey, CPGetUserKey, CryptDestroyKey


CPDuplicateKey

The CPDuplicateKey function is used to make an exact copy of a key and the state the key is in. Some keys have an associated state such as example, an initialization vector or a salt value.

BOOL CPDuplicateKey(
  HCRYPTPROV hProv,    // in
  HCRYPTKEY hKey,      // in
  DWORD *pdwReserved,  // in
  DWORD dwFlags,       // in
  HCRYPTKEY* phKey     // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
The handle to the key to be duplicated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
Flag values. This parameter is reserved for future use and should always be zero.
phKey
Address of the handle to the duplicated key.

Return Values

If the function succeeds, the return value is TRUE; Otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_CALL_NOT_IMPLEMENTED | Because this is a new function, existing CSPs may not implement it. This error is returned if the CSP does not support this function.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_KEY | The handle to the original key is not valid.

Remarks

CPDuplicateKey is used to make copies of keys and the exact state of the key. For example, a caller may want to encrypt two separate messages with the same key, but with different salt values. The key could be generated, a duplicate would be made with the CPDuplicateKey function, and then the appropriate salt value would be set on each key with the CPSetKeyParam function.

CPDestroyKey must be called to destroy any keys that are created with CPDuplicateKey. Destroying the original key does not cause the duplicate key to be destroyed. Once a duplicate key is made, it is separate from the original key. There is no shared state between the two keys.

See Also

CPDestroyKey, CryptDuplicateKey


CPExportKey

The CPExportKey function is used to export cryptographic keys out of the CSP in a secure manner.

BOOL CPExportKey(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey,    // in
  HCRYPTKEY hExpKey, // in
  DWORD dwBlobType,  // in
  DWORD dwFlags,     // in
  BYTE *pbData,      // out
  DWORD *pdwDataLen  // in, out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the key to be exported.
hExpKey
Handle to a cryptographic key belonging to the destination user. The key data within the key blob created is encrypted using this key. This ensures that only the destination user will be able to make use of the key blob.

Most often, this will be the key exchange public key of the destination user. Certain protocols, however, require that a session key belonging to the destination user be used for this purpose.

If the key blob is not to be encrypted (for example, the key blob type is PUBLICKEYBLOB), then this parameter is unused, and should be zero.

dwBlobType
Type of key blob to be exported. The following three key blob types are currently defined:
  • SIMPLEBLOB—used to transport session keys
  • PUBLICKEYBLOB—used to transport public keys
  • PRIVATEKEYBLOB—used to transport public/private key pairs

Additional key blob types will be defined as needed.

dwFlags
Flag values. No flags are currently defined.
pbData
Buffer into which the function places the key blob.

If this parameter is NULL, then no data should be copied. Instead, the required buffer size (in bytes) should be returned in pdwDataLen. This is not an error.

pdwDataLen
Address of the key blob length. Upon function entry, this contains the number of bytes in the pbData buffer. Upon exit, this must be set to the number of bytes of data copied to the pbData buffer.

If the buffer specified by pbData is not large enough to hold the key blob data, the ERROR_MORE_DATA error code should be returned via the SetLastError function. In this case, the required buffer size must be returned in pdwDataLen.

If this function fails with any error code other than ERROR_MORE_DATA, zero should be returned in this parameter.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_MORE_DATA | The pbData buffer is not large enough to hold the requested data.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_KEY | One or both of the keys specified by hKey and hExpKey are invalid.
NTE_BAD_KEY_STATE | You do not have permission to export the key. That is, when the hKey key was created, the CRYPT_EXPORTABLE flag was not specified.
NTE_BAD_PUBLIC_KEY | The key blob type specified by dwBlobType is PUBLICKEYBLOB but hExpKey does not contain a public key handle.
NTE_BAD_TYPE | The dwBlobType parameter specifies an unknown blob type.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot now be found.
NTE_NO_KEY | A session key is being exported and the hExpKey parameter does not specify a public key.

See Also

CPImportKey, CryptExportKey


CPGenKey

The CPGenKey function generates random cryptographic keys.

BOOL CPGenKey(
  HCRYPTPROV hProv, // in
  ALG_ID Algid,     // in
  DWORD dwFlags,    // in
  HCRYPTKEY *phKey  // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
Algid
Identifier for the algorithm for which the key is to be generated. This algorithm must be one of those supported by this CSP.

If a session key is to be generated, this value specifies an encryption algorithm, such as:

  • CALG_RC2
  • CALG_RC4
  • CALG_DES

If a public/private key pair is to be generated, this value specifies a key pair type, such as:

  • AT_KEYEXCHANGE
  • AT_SIGNATURE
dwFlags
Flags specifying attributes pertaining to the key generated. The sizes of RSA signature and key exchange keys may be set when the key is generated. The key size is set with the upper 16 bits of the dwFlags parameter and these 16 bits represent the length of the modulus in bits. This applies to the Microsoft Cryptographic Base Provider.The flags currently defined are:
CRYPT_EXPORTABLE
When a session key is created and this flag is not set, the CSP should refuse to export the key. If the application attempts to export the key (via CPExportKey) then the NTE_BAD_KEY_STATE error code should be returned.

This flag only applies to the export of session keys and private keys. It does not apply to public keys, which are always exportable.

CRYPT_CREATE_SALT
When this flag is set, the new session key will be assigned a random salt value automatically.

If this flag is not set, then the session key will be given a salt value of zero.

This flag does not apply to public/private key pairs.

CRYPT_NO_SALT
Specifies that a no salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft Cryptographic Providers--Release Notes.
CRYPT_USER_PROTECTED
When this flag is set, the CSP is to notify the user directly, via a dialog box or some other method, when certain actions are attempted using this key. The precise behavior is specified by the CSP (or possibly the CSP type) that is used. Prior to Microsoft Internet Explorer 4.0, the Microsoft Cryptographic Providers ignore this flag. Starting with Microsoft Internet Explorer 4.0, Microsoft Providers support this flag value.
CRYPT_PREGEN
Specifies an initial Diffie-Hellman or DSS key generation. Currently only useful with Diffie-Hellman/DSS CSPs.
phKey
Address to which the function is to copy a handle to the newly generated key.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_FAIL | The function failed in some unexpected way.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_PERM | An attempt was made to create a key pair when CRYPT_VERIFYCONTEXT was specified.

Remarks

If no key container is currently open (for example, the CRYPT_VERIFYCONTEXT flag was set in the CPAcquireContext call), then applications should not be allowed to create new key pairs. Instead, the NTE_PERM error code should be returned.

The CPGenRandom function is generally used to generate the random key material. It is important that all keys generated be truly random.

When keys are generated for symmetric block ciphers, the key by default will be set up in cipher block chaining (CBC) mode with an initialization vector of zero. This cipher mode provides a good default method for bulk encrypting data. These parameters are changed by using the CPSetKeyParam function.

See Also

CPDestroyKey, CPExportKey, CPImportKey, CryptGenKey


CPGenRandom

The CPGenRandom function fills a buffer with random bytes.

BOOL CPGenRandom(
  HCRYPTPROV hProv,  // in
  DWORD dwLen,       // in
  BYTE *pbBuffer     // in, out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
dwLen
Number of bytes of random data to be generated.
pbBuffer
Buffer to which the function is to copy the random data. This buffer is dwLen bytes in length.

Upon input to the function, this buffer may contain up to dwLen bytes of random data that the CSP can use in generating a random seed. This is discussed further in the "Remarks" section.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_FAIL | The function failed in some unexpected manner.

Remarks

Although CPGenRandom is one of the more difficult functions to implement correctly, it must be done correctly to maintain the security of your CSP. The CPGenRandom function is (typically) used internally by the CPGenKey function, as well by applications when generating data items used in cryptographic protocols, such as challenge strings. If the value of the cryptographic keys or challenge strings produced by your CSP is in any way predictable, then your CSP is not doing its job.

There are two components to a good random number generator: a method of getting a truly random seed and an algorithm that will generate a good pseudo-random stream of data based on the seed.

Generating a truly random seed can be difficult, depending on the hardware that your CSP is running on. If your CSP has access to a hardware random number source (such as some slightly radioactive material and a Geiger counter), then this doesn't present much of a problem. If your CSP is completely software-based, some of the following sources may be used:

  • The system time.
  • Any high-precision clocks that exist on the system board and peripherals.
  • The cursor or mouse pointer location.
  • Any accumulated physical state information in keyboard input buffers, I/O service queues, video drivers, and so on.
  • The number of tasks in the OS scheduling queue, their task identifiers, or their code base addresses and sizes.
  • Data from the application, passed into the CryptGenRandom function.

All of this data can be hashed together, along with the random seed from the previous session, to make a fairly good random seed. A new seed should be generated periodically throughout the session, to avoid placing too much reliance on the pseudo-random stream generator.

Once the random seed has been obtained, any number of algorithms can be used to generate a pseudo-random stream of data based on it. Sometimes a stream cipher such as RC4 is used for this purpose (with the seed forming the keying material). The following sources describe other algorithms and techniques:

  • Bellare, M., and P. Rogaway. Optimal Asymmetric Encryption. Advances in Cryptology—EUROCRYPT '94, ed. by A. deSantis, Springer-Verlag, 1995, pp. 92-111, Lecture Notes in Computer Science, vol. 950.
  • Blum, L. , M. Blum, and M. Shub. A Simple Unpredictable Pseudo-Random Number Generator. SIAM Journal on Computing 15(2)(May 1986); 364-383.
  • M. Blum and S. Micali, "How to generate cryptographically strong sequences of pseudo-random bits," SIAM Journal on Computing 13(4)(November 1984); 850-864.

See Also

CryptGenRandom


CPGetKeyParam

The CPGetKeyParam function is used by applications to retrieve data that governs the operations of a key.

BOOL CPGetKeyParam(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey,    // in
  DWORD dwParam,     // in
  BYTE *pbData,      // out
  DWORD *pdwDataLen, // in, out
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the key on which to query parameters.
dwParam
Parameter number. See the "Remarks" section for the list of currently defined parameters.
pbData
Parameter data buffer. The function copies the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

If this parameter is NULL, then no parameter data should be copied. Instead, the required buffer size (in bytes) should be returned in pdwDataLen. This is not an error.

pdwDataLen
Address of the parameter data length. Upon function entry, this contains the number of bytes in the pbData buffer. Upon exit, this must be set to the number of bytes of parameter data copied to the pbData buffer.

If the buffer specified by pbData is not large enough to hold the requested data, the ERROR_MORE_DATA error code should be returned via the SetLastError function. In this case, the required buffer size must be returned in pdwDataLen.

If this function fails with any error code other than ERROR_MORE_DATA, zero should be returned in this parameter.

dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_MORE_DATA | The pbData buffer is not large enough to hold the requested data.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_KEY or NTE_NO_KEY | The key specified by the hKey parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot now be found.

Remarks

For all key types, the dwParam value can be set to one of the following key parameter types:

KP_ALGID
Key algorithm. An algorithm specifier (ALG_ID) indicating the algorithm used by this key object should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.
KP_BLOCKLEN
If hKey references a session key, a DWORD value indicating the block length, in bits, of the cipher should be placed in the pbData buffer. For stream ciphers, this value will always be zero. A value of 4 should be returned in pdwDataLen.

If hKey references a public/private key pair, a DWORD value indicating the key pair's encryption granularity in bits should be placed in the pbData buffer. For RSA key pairs, this will be the size of the modulus. If the public-key algorithm does not support encryption, the NTE_BAD_TYPE error code should be returned.

KP_SALT
The salt value. A BYTE array containing the key's current salt value should be placed in the pbData buffer. The size of the salt value, in bytes, should be returned in pdwDataLen.

This parameter does not apply to public/private key pairs. If hKey references a public/private key pair, the NTE_BAD_TYPE error code should be returned.

KP_PERMISSIONS
Key permissions. A DWORD value containing the key's permission flags should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen. Refer to the following table for a description of each of these flags.

The following table lists the permission flags that are currently defined.
Permission flag | Description
CRYPT_ENCRYPT | Allows encryption
CRYPT_DECRYPT | Allows decryption
CRYPT_EXPORT | Allows key to be exported
CRYPT_READ | Allows parameters to be read
CRYPT_WRITE | Allows parameters to be set
CRYPT_MAC | Allows MACs to be used with key

If the hKey parameter refers to a block cipher session key, the dwParam value may also be set to one of the following parameter types:

KP_IV
The initialization vector (IV). A BYTE array containing the key's current IV should be placed in the pbData buffer. The size of the IV, in bytes, should be returned in pdwDataLen.
KP_PADDING
The padding mode. A DWORD value containing the padding method used by the key's cipher should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.

The following padding mode is currently defined:

PKCS5_PADDING—PKCS 5 (sec 6.2) padding method.

KP_MODE
The cipher mode. A DWORD value containing the mode of the cipher should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.

The following table lists the cipher modes that are currently defined.
Cipher mode | Description
CRYPT_MODE_ECB | Electronic codebook
CRYPT_MODE_CBC | Cipher block chaining
CRYPT_MODE_OFB | Output feedback mode
CRYPT_MODE_CFB | Cipher feedback mode

KP_MODE_BITS
The number of bits to feed back. A DWORD value containing the feedback width, in bits, should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.

This parameter only applies when the OFB or CFB cipher modes are used.

KP_EFFECTIVE_KEYLEN
For a CSP to be compatible with the Microsoft base providers implementation of RC2, it should support KP_EFFECTIVE_KEYLEN. It is used to query the effective key length of an RC2 key. The value of the effective key length is returned as a DWORD pointed to by the pbData parameter.

Additional parameters can be added as needed. If these are general-purpose in nature, rather than applying to a single provider type, you should define these in coordination with Microsoft. This will promote cross-vendor standardization, and allow the new parameter numbers to be added to the standard Microsoft Win32® header files.

See Also

CPSetKeyParam, CryptGetKeyParam


CPGetUserKey

The CPGetUserKey function retrieves a handle to one of the permanent key pairs in the hProv key container, such as the key exchange key pair.

BOOL CPGetUserKey(
  HCRYPTPROV hProv,     // in
  DWORD dwKeySpec,      // in
  HCRYPTKEY *phUserKey  // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
dwKeySpec
Specification of the key to retrieve. The following key pair types are currently defined:
  • AT_KEYEXCHANGE—key exchange key pair
  • AT_SIGNATURE—digital signature key pair
phUserKey
Address to which the function copies the handle of the retrieved key.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_KEY | The key specified by the hKey parameter is invalid.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot now be found.
NTE_NO_KEY | The key specified by the dwKeySpec parameter does not exist.

See Also

CPExportKey, CPGenKey, CryptGetUserKey


CPImportKey

The CPImportKey function is used to transfer a cryptographic key from a key blob to the CSP.

BOOL CPImportKey(
  HCRYPTPROV hProv,   // in
  CONST BYTE *pbData, // in
  DWORD dwDataLen,    // in
  HCRYPTKEY hImpKey,  // in
  DWORD dwFlags,      // in
  HCRYPTKEY *phKey    // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
pbData
Buffer containing the key blob. This key blob was generated by the CPExportKey function, either by this CSP or by some other CSP running on a distant computer.

This key blob consists of a standard header followed by the (often encrypted) key material.

dwDataLen
Length (in bytes) of the key blob.
hImpKey
The meaning of this parameter differs, depending on the CSP type and the type of key blob being imported.

If a signed key blob is being imported, the key is used to validate the signature of the key blob. In this case, this parameter should contain a handle to the key exchange public key of the party that created the key blob.

If the key blob is encrypted with the key exchange key pair (for example, a SIMPLEBLOB), then this parameter may be the handle to the key exchange key.

If the key blob is encrypted with a session key (as is often done by Fortezza CSPs, for example), then this parameter should contain a handle to this session key.

If the key blob is not encrypted (for example, a PUBLICKEYBLOB) , then this parameter is not used, and should be set to zero.

dwFlags
The flag values. This parameter is currently used only when a public/private key pair is being imported into the CSP (in the form of a PRIVATEKEYBLOB). In this case, if the key being imported is eventually to be re-exported, then the CRYPT_EXPORTABLE flag must be placed in this parameter. If this flag is not used then calls to CryptExportKey with the key handle will fail.

CRYPT_NO_SALT. Specifies that a no-salt value gets allocated for a 40-bit symmetric key. For more information, see Microsoft Cryptographic Providers— Release Notes.

phKey
Address to which the function copies a handle to the key that was imported.

Return Values

If the function succeeds TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The simple key blob being imported is not encrypted with the expected key exchange algorithm. The most likely cause of this error is incompatible CSPs.
NTE_BAD_DATA | The algorithm of the public key being imported is not supported by this CSP.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_TYPE | The key blob type is not supported by this CSP and is possibly invalid.
NTE_BAD_UID | The hProv parameter does not contain a valid context handle.
NTE_BAD_VER | The key blob's version number indicates a key blob version that the CSP does not support.

See Also

CPExportKey, CPGenKey, CryptImportKey


CPSetKeyParam

The CPSetKeyParam function allows applications to customize various aspects of the operations of a key.

BOOL CPSetKeyParam(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey,    // in
  DWORD dwParam,     // in
  BYTE *pbData,      // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the key on which to set parameters.
dwParam
Parameter number. Currently, the following parameters have been defined:
  • KP_SALT
  • KP_SALT_EX
  • KP_PERMISSIONS
  • KP_EFFECTIVE_KEYLEN
  • KP_IV
  • KP_PADDING
  • KP_MODE
  • KP_MODE_BITS

These are described along with the CPGetKeyParam function.

Additional parameters can be added as needed. If these are general-purpose in nature, rather than applying to a single provider type, you should define these in coordination with Microsoft. This will promote cross-vendor standardization, and allow the new parameter numbers to be added to the standard Win32 header files.

pbData
Parameter data buffer. Upon entry to the function, this buffer will contain the data that corresponds to the dwParam parameter number. Notice that the length of this data is not specified explicitly, but instead is implied by the dwParam parameter number.
dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The dwFlags parameter is non-zero or the pbData buffer contains an invalid value.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot now be found.
NTE_FAIL | The function failed in some unexpected manner.

See Also

CPGenKey, CPGetKeyParam, CryptSetKeyParam


Data Encryption Functions

The functions in this chapter support encryption and decryption operations. The following table briefly describes each function.

Function | Description
CPDecrypt | Decrypt a section of ciphertext by using the specified encryption key.
CPEncrypt | Encrypt a section of plaintext by using the specified encryption key.


CPDecrypt

The CPDecrypt function is used to decrypt data that was previously encrypted with the CPEncrypt function. Optionally, the application can specify that a hash of the data is to be generated at the same time.

BOOL CPDecrypt(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey,    // in
  HCRYPTHASH hHash,  // in
  BOOL Final,        // in
  DWORD dwFlags,     // in
  BYTE *pbData,      // in, out
  DWORD *pdwDataLen  // in, out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the session key to be used for the decryption. This key specifies the decryption algorithm that is to be used.
hHash
Handle to a hash object. This parameter is used only if a hash of the data is to be computed at the same time the data is being decrypted.

If no hash is to be done, this parameter should be zero.

Final
Boolean value that specifies whether this is the last section in a series being decrypted. This will be TRUE if this is the last (or only) block, and FALSE otherwise.
dwFlags
Flag values. No flags are currently defined.
pbData
Buffer holding the data to be decrypted. Once the decryption has been performed, the plaintext is to be placed back in this same buffer. If a block cipher is used and dwFlags is TRUE, any padding data should be removed before returning the plaintext to the application.

This is somewhat simpler than the encryption case, since the plaintext generated is never larger than the ciphertext.

pdwDataLen
Address of the data length. Upon function entry, this specifies the number of bytes of ciphertext in the pbData buffer. If a block cipher is used and Final is FALSE, this value must be a multiple of the cipher block length. In other words, the CPDecrypt function is not required to buffer any data internally.

Upon exit, this parameter should indicate the number of bytes of plaintext placed in the pbData buffer.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The hKey session key specifies an algorithm that this CSP does not support.
NTE_BAD_DATA | The data to be decrypted is invalid. For example, when a block cipher is used and the Final flag is FALSE, the value specified by pdwDataLen must be a multiple of the block size. This error may also be returned when the padding is found to be invalid.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hHash parameter contains an invalid handle.
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a session key.
NTE_BAD_LEN | The size of the output buffer is too small to hold the generated plaintext.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot now be found.
NTE_DOUBLE_ENCRYPT | The application attempted to decrypt the same data twice.
NTE_FAIL | The function failed in some unexpected way.

See Also

CPEncrypt, CPGenKey, CryptDecrypt


CPEncrypt

The CPEncrypt function is used to encrypt data. Optionally, the application can specify that a hash of the data is to be generated at the same time.

BOOL CPEncrypt(
  HCRYPTPROV hProv,  // in
  HCRYPTKEY hKey,    // in
  HCRYPTHASH hHash,  // in
  BOOL Final,        // in
  DWORD dwFlags,     // in
  BYTE *pbData,      // in, out
  DWORD *pdwDataLen, // in, out
  DWORD dwBufLen     // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hKey
Handle to the session key that is to used for the encryption. This key specifies the encryption algorithm that is to be used.
hHash
Handle to a hash object. This parameter is used only if a hash of the data is to be computed at the same time the data is being encrypted.

If no hash is to be done, this parameter should be zero.

Final
Boolean value that specifies whether this is the last section in a series being encrypted. This will be TRUE if this is the last (or only) block, and FALSE otherwise.
dwFlags
Flag values. No flags are currently defined.
pbData
Buffer holding the data to be encrypted. Once the encryption has been performed, the ciphertext is to be placed back in this same buffer.
pdwDataLen
Address of the data length. Upon function entry, this specifies the number of bytes of plaintext in the pbData buffer. If a block cipher is used and dwFlags is FALSE, then this value must be a multiple of the cipher block length. In other words, the CPEncrypt function is not required to buffer any data internally.

Upon exit, this parameter should indicate the number of bytes of ciphertext that the function placed in the pbData buffer.

When a block cipher is used, the size of the ciphertext generated is sometimes larger than that of the plaintext. However, it must never be larger than dwBufLen.

dwBufLen
Size (in bytes) of the pbData buffer.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The hKey session key specifies an algorithm that this CSP does not support.
NTE_BAD_DATA | The data to be encrypted is invalid. For example, when a block cipher is used and the Final flag FALSE, the value specified by pdwDataLen must be a multiple of the block size.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hHash parameter contains an invalid handle.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked "finished."
NTE_BAD_KEY | The hKey parameter does not contain a valid handle to a key.
NTE_BAD_LEN | The size of the output buffer is too small to hold the generated ciphertext.
NTE_BAD_UID | The CSP context that was specified when the key was created cannot now be found.
NTE_DOUBLE_ENCRYPT | The application attempted to encrypt the same data twice.
NTE_FAIL | The function failed in some unexpected way.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

See Also

CPDecrypt, CPGenKey, CryptEncrypt


Hashing and Digital Signature Functions

The functions described in this chapter are used by applications to compute hashes (also known as message digests), as well as to create and verify digital signatures. The following table briefly describes each function.

Function | Description
CPCreateHash | Creates an "empty" hash object.
CPDestroyHash | Destroys a hash object.
CPDuplicateHash | Makes an exact copy of a hash and the state the hash is in.
CPGetHashParam | Retrieves a hash object parameter.
CPHashData | Hashes a block of data, adding it to the specified hash object.
CPHashSessionKey | Hashes a session key, adding it to the specified hash object.
CPSetHashParam | Sets a hash object parameter.
CPSignHash | Signs the specified hash object.
CPVerifySignature | Verifies a digital signature.


CPCreateHash

The CPCreateHash function is used by applications to initiate the hashing of a stream of data.

BOOL CPCreateHash(
  HCRYPTPROV hProv,  // in
  ALG_ID Algid,      // in
  HCRYPTKEY hKey,    // in
  DWORD dwFlags,     // in
  HCRYPTHASH *phHash // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
Algid
Algorithm identifier of the hash algorithm to be used.
hKey
If the type of hash algorithm is a keyed hash (such as a MAC algorithm), the session key for the hash is passed in this parameter. For non-keyed algorithms, this parameter should be set to zero.
dwFlags
Flag values. No flags are currently defined.
phHash
Address to which the function copies a handle to the new hash object.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The Algid parameter specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_KEY | A keyed hash algorithm (for example, CALG_MAC) is specified by Algid, and the hKey parameter is either zero or it specifies an invalid key handle. This error code will also be returned if the key is to a stream cipher, or if the cipher mode is one that doesn't use feedback.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

See Also

CPDestroyHash, CPHashData, CryptCreateHash


CPDestroyHash

The CPDestroyHash function destroys the hash object referenced by the hHash parameter.

BOOL CPDestroyHash(
  HCRYPTPROV hProv, // in
  HCRYPTHASH hHash  // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to the hash object to be destroyed.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot now be found.

See Also

CPCreateHash, CryptDestroyHash


CPDuplicateHash

The CPDuplicateHash function is used to make an exact copy of a hash and the state the hash is in.

BOOL CPDuplicateHash(
  HCRYPTPROV hProv,    // in
  HCRYPTHASH hHash,    // in
  DWORD *pdwReserved,  // in
  DWORD dwFlags,       // in
  HCRYPTHASH phHash    // out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
The handle to the hash to be duplicated.
pdwReserved
This parameter is reserved for future use and must be NULL.
dwFlags
The flag values. This parameter is reserved for future use and should always be zero.
phHash
The address of the handle to the duplicated hash.

Return Values

If the function succeeds, the return value is TRUE; Otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_CALL_NOT_IMPLEMENTED | Since this is a new function, existing CSPs may not implement it. This error is returned if the CSP does not support this function.
ERROR_INVALID_PARAMETER | One of the parameters contains an invalid value. This is most often an illegal pointer.
NTE_BAD_HASH | The handle to the original hash is not valid.

Remarks

CPDuplicateHash is used to make copies of hashes (also known as message digests) and the exact state of the hash. For example a caller may want to generate two hashes, but both hashes have to start with some common data hashed. A hash could be created, the common data hashed, a duplicate made with the CPDuplicateHash function, and then the data unique to each hash would be hashed. The handle to the duplicated hash, phHash, allows the developer to utilize the duplicated hash independently of the original hash.

CPDestroyHash must be called to destroy any hashes that are created with CPDuplicateHash. Destroying the original hash does not cause the duplicate hash to be destroyed. Once a duplicate hash is made, it is separate from the original hash. There is no shared state between the two hashes.

See Also

CPDestroyHash, CryptDuplicateHash


CPGetHashParam

The CPGetHashParam function allows applications to retrieve data that governs the operations of a hash object. The actual hash value is also obtained via this function.

BOOL CPGetHashParam(
  HCRYPTPROV hProv,  // in
  HCRYPTHASH hHash,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // out
  DWORD *pdwDataLen, // in, out
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to the hash object on which to query parameters.
dwParam
Parameter number. See the "Remarks" section for the list of currently defined parameters.
pbData
Parameter data buffer. The function copies the specified parameter data to this buffer. The form of this data will vary, depending on the parameter number.

If this parameter is NULL, then no parameter data should be copied. Instead, the required buffer size (in bytes) should be returned in pdwDataLen. This is not an error.

pdwDataLen
Address of the parameter data length. Upon function entry, this contains the number of bytes in the pbData buffer. Upon exit, this must be set to the number of bytes of parameter data copied to the pbData buffer.

If the buffer specified by pbData is not large enough to hold the requested data, the ERROR_MORE_DATA error code should be returned via the SetLastError function. In this case, the required buffer size must be returned in pdwDataLen.

If this function fails with any error code other than ERROR_MORE_DATA, zero should be returned in this parameter.

dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_MORE_DATA | The pbData buffer is not large enough to hold the requested data.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter number.
NTE_BAD_UID | The CSP context that was specified when the hash was created cannot now be found.

Remarks

The dwParam value can be set to one of the following hash parameter types:

HP_ALGID
The hash algorithm. An algorithm specifier (ALG_ID) indicating the algorithm used by this hash object should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.
HP_HASHSIZE
The hash value size. A DWORD specifying the number of bytes in the hash value produced by this hash object should be placed in the pbData buffer. A value of 4 should be returned in pdwDataLen.
HP_HASHVAL
The hash value (or message digest). The hash value should be computed and placed in the pbData buffer. The length of the hash value should be returned in pdwDataLen.

The pbData buffer will contain the hash value or message digest for the hash object specified by hHash. This value is generated based on the data supplied earlier to the hash object through the CryptHashData and CryptHashSessionKey functions (both in the CryptoAPI).

After this parameter has been retrieved, the application shouldn't be allowed to add more data to the hash object.

Additional parameters can be added as needed. If these are general-purpose in nature, rather than applying to a single provider type, you should define these in coordination with Microsoft. This will promote cross-vendor standardization, and allow the new parameter numbers to be added to the standard Win32 header files.

See Also

CPCreateHash, CPGetKeyParam, CPSetHashParam, CryptGetHashParam


CPHashData

The CPHashData function is used by applications to feed data to a specified hash object.

BOOL CPHashData(
  HCRYPTPROV hProv,    // in
  HCRYPTHASH hHash,    // in
  CONST BYTE *pbData,  // in
  DWORD dwDataLen,     // in
  DWORD dwFlags        // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to a hash object. An application obtains this handle by using the CryptCreateHash function (in the CryptoAPI).
pbData
Address of the data to be hashed.
dwDataLen
Number of bytes of data to be hashed. This must be zero if the CRYPT_USERDATA flag is set.
dwFlags
Flag values. The following value is currently defined:
CRYPT_USERDATA
When this flag is set, the CSP should prompt the user to enter some data directly, which is then added to the hash. The application is not allowed access to the data. For example, this flag can be used to allow the user to enter a PIN into the system.

Support for this flag is optional.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The hHash handle specifies an algorithm that this CSP does not support.
NTE_BAD_FLAGS | The dwFlags parameter contains an invalid value.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked as "finished."
NTE_BAD_KEY | A keyed hash algorithm is being used, but the session key is no longer valid. This error will be generated if the session key is destroyed before the hashing operating is complete.
NTE_BAD_LEN | The CRYPT_USERDATA flag is set, and the dwDataLen parameter has a non-zero value.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot now be found.
NTE_FAIL | The function failed in some unexpected way.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

See Also

CPCreateHash, CPHashSessionKey, CryptHashData


CPHashSessionKey

The CPHashSessionKey function is used by applications to feed a cryptographic key to a specified hash object. This allows session keys to be hashed without the application having access to the key material.

BOOL CPHashSessionKey(
  HCRYPTPROV hProv,  // in
  HCRYPTHASH hHash,  // in
  HCRYPTKEY hKey,    // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to a hash object. An application obtains this handle by using the CryptCreateHash function (in the CryptoAPI).
hKey
Handle to the session key object to be hashed.
dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_ALGID | The hHash handle specifies a hash algorithm that this function does not support.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_HASH_STATE | An attempt was made to add data to a hash object that is already marked as "finished."
NTE_BAD_KEY | A keyed hash algorithm is being used, but the session key is no longer valid. This error will be generated if the session key passed to CPCreateHash is destroyed before the hashing operating is complete.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot now be found.
NTE_FAIL | The function failed in some unexpected way.

Remarks

The only data that this function is to add to the hash object is the session key material itself. If necessary, the application itself can hash in the key's salt, initialization vector, and so on. Depending on the CSP type, the key material may need to be formatted or padded in some specific way before being added to the hash. This is discussed further in Interoperability with RSA CSPs.

See Also

CPCreateHash, CPGenKey, CPHashData, CryptHashSessionKey


CPSetHashParam

The CPSetHashParam function allows applications to customize various aspects of the operations of a hash object.

BOOL CPSetHashParam(
  HCRYPTPROV hProv,  // in
  HCRYPTHASH hHash,  // in
  DWORD dwParam,     // in
  BYTE *pbData,      // in
  DWORD dwFlags      // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to the hash object on which to set parameters.
dwParam
Parameter number. See the "Remarks" section for the list of currently defined parameters.
pbData
Parameter data buffer. Upon entry to the function, this buffer will contain the data that corresponds to the dwParam parameter number. Notice that the length of this data is not specified explicitly, but instead is implied by the dwParam parameter number.
dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The dwFlags parameter is non-zero or the pbData buffer contains an invalid value.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_TYPE | The dwParam parameter specifies an unknown parameter.
NTE_BAD_UID | The CSP context that was specified when the hKey key was created cannot now be found.
NTE_FAIL | The function failed in some unexpected way.

Remarks

The dwParam parameter can be set to one of the following values:

HP_HASHVAL
Hash value. The pbData buffer should contain a byte array containing a hash value. This data should be of the same size and format as the hash value returned by the CPGetHashParam function. This data is placed directly into the hash object.

Typically, the hash object specified by hHash will have just been created. If this isn't the case (that is, data has already been added to the hash object), an error may be returned.

This parameter was defined to give applications the ability to sign hash values, without having access to the base data. Because the application (much less the user) can have no idea what is being signed, this operation is intrinsically risky. It is envisioned that many CSPs will not support this parameter.

Additional parameters can be added as needed. If these are general-purpose in nature, rather than just applying to a single provider type, you should define these in coordination with Microsoft. This will promote cross-vendor standardization, and allow the new parameter numbers to be added to the standard Win32 header files.

See Also

CPCreateHash, CPGetHashParam, CPSignHash, CryptSetHashParam


CPSignHash

The CPSignHash function is used by applications to sign hash values.

BOOL CPSignHash(
  HCRYPTPROV hProv,      // in
  HCRYPTHASH hHash,      // in
  DWORD dwKeySpec,       // in
  LPCWSTR sDescription,  // in
  DWORD dwFlags,         // in
  BYTE *pbSignature,     // out
  DWORD *pdwSigLen       // in, out
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to the hash object to be signed.
dwKeySpec
Key pair that is to be used to sign the hash. The following values are currently defined:
  • AT_KEYEXCHANGE—key exchange key pair
  • AT_SIGNATURE—digital signature key pair
sDescription
Applications should no longer be using this parameter and should be set to NULL to prevent security vulnerabilities. However, CSPs may prefer to keep supporting it for backward compatibility with the Microsoft Providers.
dwFlags
Flag values. No flags are currently defined.
pbSignature
Buffer into which the signature data is to be placed.

If this parameter is NULL, then the signature operation is not performed. Instead, the required buffer size (in bytes) should be returned in pdwSigLen. This is not an error.

pdwSigLen
Address of the signature data length. Upon function entry, this contains the number of bytes in the pbSignature buffer. Upon exit, this must be set to the number of bytes of data copied to the pbSignature buffer.

If the buffer specified by pbSignature is not large enough to hold the signature, the ERROR_MORE_DATA error code should be returned via the SetLastError function. In this case, the required buffer size must be returned in pdwDataLen.

If this function fails with any error code other than ERROR_MORE_DATA, zero should be returned in this parameter.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
ERROR_MORE_DATA | The pbData buffer is not large enough to hold the requested data.
NTE_BAD_ALGID | The hHash handle specifies a hash algorithm that this function does not support.
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot now be found.
NTE_NO_KEY | The private key specified by dwKeySpec does not exist.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Remarks

Depending on the key pair that is to be used, many CSPs will ask the user directly before performing the signature operation. When this is the case, the sDescription string, if supported, should be displayed to the user so that he or she knows what is being signed.

The CPSignHash function typically performs the following steps internally:

  • The hash object is "finished," and the hash value extracted.
  • The hash value is padded out as required by the signature algorithm.
  • The actual signing operation is performed.

The application should not be allowed to add more data to the hash object after it has been signed. However, the application is still responsible for calling the CPDestroyHash function.

See Also

CPCreateHash, CPHashData, CPVerifySignature, CryptSignHash


CPVerifySignature

The CPVerifySignature function is used to verify a digital signature against a hash object.

BOOL CPVerifySignature(
  HCRYPTPROV hProv,      // in
  HCRYPTHASH hHash,      // in
  CONST BYTE *pbSignature,  // in
  DWORD dwSigLen,        // in
  HCRYPTKEY hPubKey,     // in
  LPCWSTR sDescription,  // in
  DWORD dwFlags          // in
);

Parameters

hProv
Handle to a particular key container (or "context") within the CSP. This handle is obtained via a call to CPAcquireContext.
hHash
Handle to the hash object to verify against.
pbSignature
Buffer containing the signature data to be verified.
dwSigLen
Length (in bytes) of the signature data.
hPubKey
Handle to the public key to be used to verify the signature.
sDescription
Applications should no longer be using this parameter and should be set to NULL to prevent security vulnerabilities. However, CSPs may prefer to keep supporting it for backward compatibility in the Microsoft Providers.
dwFlags
Flag values. No flags are currently defined.

Return Values

If the function succeeds, TRUE should be returned; otherwise, return FALSE. When FALSE is returned, the appropriate error code (see the following table) must be set via SetLastError.

Error | Description
NTE_BAD_FLAGS | The dwFlags parameter is non-zero.
NTE_BAD_HASH | The hash object specified by the hHash parameter is invalid.
NTE_BAD_KEY | The hPubKey parameter does not contain a handle to a valid public key.
NTE_BAD_SIGNATURE | The signature failed to verify. This could be because the data itself has changed, the description string did not match, or the wrong public key was specified by hPubKey. This error may also be returned if the hashing or signature algorithms don't match the ones used to create the signature.
NTE_BAD_UID | The CSP context that was specified when the hash object was created cannot now be found.
NTE_NO_MEMORY | The CSP ran out of memory during the operation.

Remarks

The CPVerifySignature function typically performs the following steps internally:

  • The sDescription description string, if supported, is added to the hash object.
  • The hash object is "finished," and the hash value extracted.
  • The hash value is padded out as required by the signature algorithm.
  • The actual verification operation is performed by using the hPubKey public key. The NTE_BAD_SIGNATURE error code is returned if the signed hash within the pbSignature buffer and the hash value in the hHash hash object do not match.

The application should not be allowed to add more data to the hash object after the verification has been performed. However, the application is still responsible for calling the CPDestroyHash function.

See Also

CPCreateHash, CPHashData, CPSignHash, CryptVerifySignature


RSA/Schannel CSP Overview

This section defines the RSA/Schannel Cryptographic Service Provider (CSP) type and describes the functionality that must be supported in order to be compatible with future versions of the Microsoft® cryptographic protocol engine (Schannel.dll).

The information presented in the following sections is intended for developers who plan to implement a compatible RSA/Schannel CSP. Readers should have a basic familiarity with Secure Socket Layer (SSL) version 3.0 protocol, public-key cryptography, digital certificates, and the Microsoft CryptoAPI function set. Before proceeding, readers who are new to these topics are advised to read the SSL Protocol 3.0 specification, the CryptoAPI Programmers Guide and Reference, available in the Microsoft Platform SDK, and the references provided in the Overview section of that CryptoAPI material.

The code samples in the following sections are presented from the perspective of the Microsoft protocol engine. To write a compatible CSP the reader needs to understand the SSL 3.0 specification and combine that knowledge with an understanding of the protocol engine code as presented here.

The CSP developer may choose not to support the Private Communication Technology (PCT) protocol because usage of this protocol in the future is expected to be minimal. The protocol engine supports the PCT protocol strictly for purposes of backward compatibility.

For information on how to develop a Diffie-Hellman/Schannel CSP, see Diffie-Hellman/Schannel CSP Overview.


The Protocol Engine's Contexts

The protocol engine will create one or more contexts via a call to CryptAcquireContext with the dwProvType parameter set to PROV_RSA_SCHANNEL. The dwFlags parameter will usually have the CRYPT_VERIFYCONTEXT flag set. These contexts are used to perform client-side operations as well as bulk encryption.

When Secure Socket Layer (SSL) 3.0 or Transport Layer Security (TLS) 1.0 is enabled, the protocol engine will typically create an ephemeral key container holding a 512-bit AT_KEYEXCHANGE key pair. This key pair is used when creating the ServerKeyExchange message. Because the key pair is ephemeral, the CRYPT_VOLATILE flag must be specified when the CryptGenKey function is called to create it. This call requests that the key pair not be not written to permanent storage. When an ephemeral RSA key is used, the context used to create this key will most likely be acquired by calling CryptAcquireContext with the CRYPT_VERIFYCONTEXT flag value set in the dwFlags parameter.


Enumerating the Supported Protocols

The supported protocols and cipher suites can be determined by calling CryptGetProvParam with PP_ENUMALGS_EX. This works in a manner similar to the use of PP_ENUMALGS, but returns the following structure instead of the more limited one returned when using PP_ENUMALGS.

// protocol flags
#define CRYPT_FLAG_PCT1         0x0001
#define CRYPT_FLAG_SSL2         0x0002
#define CRYPT_FLAG_SSL3         0x0004
#define CRYPT_FLAG_TLS1         0x0008

typedef struct _PROV_ENUMALGS_EX
{
    ALG_ID    aiAlgid;
    DWORD     dwDefaultLen;
    DWORD     dwMinLen;
    DWORD     dwMaxLen;
    DWORD     dwProtocols;
    DWORD     dwNameLen;
    CHAR      szName[20];
    DWORD     dwLongNameLen;
    CHAR      szLongName[40];
} PROV_ENUMALGS_EX;

The following table shows the algorithm list that might be returned by a typical (domestic) PROV_RSA_SCHANNEL CSP. Notice that neither SSL2 SHA MACs nor SSL2 DES encryption is supported by the CSP in this example.

Algid | Min | Max | Protocols | Name
CALG_RSA_KEYX | 512 | 2048 | 0x0007 | "RSA_KEYX"
CALG_MD5 | 128 | 128 | 0x0007 | "MD5"
CALG_SHA | 160 | 160 | 0x0005 | "SHA"
CALG_RC4 | 40 | 128 | 0x0007 | "RC4"
CALG_DES | 56 | 56 | 0x0005 | "DES"

Before sending a ClientHello or ServerHello message, the protocol engine will enumerate all of the algorithms and key sizes supported by the CSP and internally build a list of supported cipher suites.


Public/Private Key Pair Usage

All normal RSA operations use the AT_KEYEXCHANGE public/private key pair. Server-side protocol engines are required to have an X509 certificate that contains a matching public key. Client-side protocol engines are only required to have a certificate if they are intended to support client authentication.

The protocol engine never uses the AT_SIGNATURE public/private key pair, so that key pair need not be supported by the CSP.

In the situation where an SSL 3.0 export cipher suite is used and the AT_KEYEXCHANGE key pair is larger than 512 bits, the server must use an additional RSA key pair. This key pair is always exactly 512 bits and, at the discretion of the protocol engine, may be ephemeral. The pair is stored as an AT_KEYEXCHANGE element in a key container owned by the protocol engine. A handle to this key container is typically acquired at protocol engine startup.


The SHA/MD5 RSA Signature Type

CSPs of type PROV_RSA_SCHANNEL must support the CALG_SSL3_SHAMD5 hash type, in a manner compatible with the Microsoft base cryptographic provider.

SSL 3.0 and TLS 1.0 client authentication use the algorithm identifier CALG_SSL3_SHAMD5. The hash consists of a concatenation of a MD5 hash and a SHA hash and is signed with a RSA private key. CryptoAPI and the Microsoft providers support this with the hash type CALG_SSL3_SHAMD5. A handle to a hash value of this type is created with the CryptCreateHash function with CALG_SSL3_SHAMD5 in the Algid parameter. After a handle to the hash is obtained, the hash value is set with the CryptSetHashParam function. Calls to CryptHashData will fail with a handle to a hash of this type. Instead the data is hashed independently of this hash object with MD5 and SHA, the resulting hash values are then concatenated with the MD5 value leftmost and the SHA value rightmost. This will result in a 36 byte value (16 bytes + 20 bytes) which is set with CryptSetHashParam. The concatenated hash values are passed in the pbData parameter, and the HP_HASHVAL value must be passed in the dwParam parameter. Once the hash is set then a CryptSignHash is called to generate the signature. Finally a CryptDestroyHash is called to destroy the hash object.


Creating the Master Key

The master key is a piece of data from which all other keys are derived. Depending on the protocol and cipher suite being used, the master key is from 5 to 48 bytes in length. A master key is created by the client-side CSP and transferred to the server within an RSA envelope.

The Client Side

The Server Side

Specifying the Algorithms


The Client Side

The protocol engine's client-side code is typically:

HCRYPTPROV hProv      = <protocol engine's key container>;
HCRYPTKEY  hPublicKey = <server's public key>;
HCRYPTKEY  hMasterKey;
ALG_ID     Algid;
DWORD      dwFlags;
BYTE       rgbBlob[<max blob size>];
DWORD      cbBlob;

// Select the master key type.
switch(<protocol being used>)
{
    case <PCT 1.0>:
        Algid = CALG_PCT1_MASTER;
        dwFlags = 0;
        break;

    case <SSL 2.0>:
        Algid = CALG_SSL2_MASTER;
        if(<we support SSL3>)
            dwFlags = CRYPT_SSL2_FALLBACK;
        else
            dwFlags = 0;
        break;

    case <SSL 3.0>:
        Algid = CALG_SSL3_MASTER;
        dwFlags = 0;
        break;

    case <TLS 1.0>:
        Algid = CALG_TLS1_MASTER;
        dwFlags = 0;
        break;
}

// Generate the master key.
CryptGenKey(hProv, Algid, CRYPT_EXPORTABLE, &hMasterKey);

// Encrypt the master key.
cbBlob = sizeof(rgbBlob);
CryptExportKey(hMasterKey, hPublicKey, SIMPLEBLOB,
               dwFlags, rgbBlob, &cbBlob);


The Server Side

The protocol engine's server-side code is typically:

HCRYPTPROV hProv         = <server's key container>;
PBYTE      pbKeyExchange = <pointer to RSA envelope>;
DWORD      dwKeyExchange = <size of RSA envelope>;
HCRYPTKEY  hPublicKey;
HCRYPTKEY  hMasterKey;
ALG_ID     Algid;
DWORD      dwFlags;
BYTE       rgbBlob[<max blob size>];
DWORD      cbBlob;

// Select the master key type.
switch(<protocol being used>)
{
    case <PCT 1.0>:
        Algid = CALG_PCT1_MASTER;
        dwFlags = 0;
        break;

    case <SSL 2.0>:
        Algid = CALG_SSL2_MASTER;
        if(<we support SSL3>)
            dwFlags = CRYPT_SSL2_FALLBACK;
        else
            dwFlags = 0;
        break;

    case <SSL 3.0>:
        Algid = CALG_SSL3_MASTER;
        dwFlags = 0;
        break;

    case <TLS 1.0>:
        Algid = CALG_TLS1_MASTER;
        dwFlags = 0;
        break;
}

// Build SIMPLEBLOB around the RSA envelope.
{
     BLOBHEADER *pBlobHeader = (BLOBHEADER *)rgbBlob;
     ALG_ID     *pAlgid      = (ALG_ID *)(pBlobHeader + 1);
     BYTE       *pData       = (BYTE *)(pAlgid + 1);

     pBlobHeader->bType    = SIMPLEBLOB;
     pBlobHeader->bVersion = CUR_BLOB_VERSION;
     pBlobHeader->reserved = 0;
     pBlobHeader->aiKeyAlg = Algid;

     *pAlgid = CALG_RSA_KEYX;

     ReverseMemCopy(pData, pbKeyExchange, cbKeyExchange);
}

// Decrypt the master key.
CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hPublicKey);
CryptImportKey(hProv, rgbBlob, cbBlob, hPublicKey,
               dwFlags, &hMasterKey);
CryptDestroyKey(hPublicKey);


Specifying the Algorithms

After the master key has been created (or imported), the protocol engine must inform the CSP of the type of bulk encryption and MAC keys that will be derived from the master key. The following code specifies the algorithms. The same code is used for both client and server.

typedef struct _SCHANNEL_ALG
{
    DWORD  dwUse;
    ALG_ID Algid;
    DWORD  cBits;
} SCHANNEL_ALG, *PSCHANNEL_ALG;

SCHANNEL_ALG Algorithm;

// Specify encryption algorithm.
Algorithm.dwUse = SCHANNEL_ENC_KEY;
Algorithm.Algid = CALG_RC4;    // or CALG_RC2, CALG_DES, etc.
Algorithm.cBits = 40;          // or 64, 128, 192, etc.
CryptSetKeyParam(hMasterKey, KP_SCHANNEL_ALG, (PBYTE)&Algorithm, 0);

// Specify hash algorithm.
Algorithm.dwUse = SCHANNEL_MAC_KEY;
Algorithm.Algid = CALG_MD5;    // or CALG_SHA, etc.
Algorithm.cBits = 128;         // or 160...
CryptSetKeyParam(hMasterKey, KP_SCHANNEL_ALG, (PBYTE)&Algorithm, 0);

Note The protocol engine should never specify algorithms and key sizes unless they are supported by the CSP. See the Enumerating the Supported Protocols section. Where unsupported algorithms or key sizes are specified, the CSP should fail and return the NTE_BAD_DATA error code.


Deriving the Bulk Encryption and MAC Keys

The bulk encryption and MAC keys are mostly derived from the master key, but often include a number of other items, depending on the protocol and cipher suite used.

The process is the same for both client and server:

  1. The protocol engine calls CryptSetKeyParam on the master key one or more times, such that the CSP has all of the information necessary to build the keys.
  2. A hash object is created from the master key via CryptCreateHash. This step is necessary because it is not possible to derive CryptoAPI keys directly from other keys.
  3. The two bulk encryption keys and the two MAC keys are created from the "master hash" object, via four calls to CryptDeriveKey.

Note When performing SSL "reconnects", the protocol engine may perform the above procedure several times, using the same master key. This enables the client and server to have multiple (often simultaneous) connections, each using different bulk encryption and MAC keys, without doing any RSA operations.

As with all CSPs, it is important that good thread-safe practices are used. Thread counts of several dozen are not unusual.

The protocol engine's source code is typically;

BOOL fClient = <are we a client?>;
CRYPT_DATA_BLOB Data;
HCRYPTHASH hMasterHash;

// Finish creating the master_secret.
switch(<protocol being used>)
{
    case <PCT 1.0>:
        // Specify clear key value.
        Data.pbData = pClearKey;
        Data.cbData = cbClearKey;
        CryptSetKeyParam(hMasterKey, KP_CLEAR_KEY,
                         (PBYTE)&Data, 0);

        // Specify the CH_CHALLENGE_DATA.
        Data.pbData = pChallenge;
        Data.cbData = cbChallenge;
        CryptSetKeyParam(hMasterKey, KP_CLIENT_RANDOM,
                         (PBYTE)&Data, 0);

        // Specify the SH_CONNECTION_ID_DATA.
        Data.pbData = pConnectionID;
        Data.cbData = cbConnectionID;
        CryptSetKeyParam(hMasterKey, KP_SERVER_RANDOM,
                         (PBYTE)&Data, 0);

        // Specify the SH_CERTIFICATE_DATA.
        Data.pbData = pbServerCertificate;
        Data.cbData = cbServerCertificate;
        CryptSetKeyParam(hMasterKey, KP_CERTIFICATE,
                         (PBYTE)&Data, 0);
        break;

    case <SSL 2.0>:

        // Specify clear key value.
        Data.pbData = pClearKey;
        Data.cbData = cbClearKey;
        CryptSetKeyParam(hMasterKey, KP_CLEAR_KEY,
                         (PBYTE)&Data, 0);
        // Specify the CH_CHALLENGE_DATA.
        Data.pbData = pChallenge;
        Data.cbData = cbChallenge;
        CryptSetKeyParam(hMasterKey, KP_CLIENT_RANDOM,
                         (BYTE*)&Data, 0);

        // Specify the SH_CONNECTION_ID_DATA.
        Data.pbData = pConnectionID;
        Data.cbData = cbConnectionID;
        CryptSetKeyParam(hMasterKey, KP_SERVER_RANDOM,
                         (BYTE*)&Data, 0);

        break;

case <SSL 3.0>:
case <TLS 1.0>:

        // Specify client_random.
        Data.pbData = pClientRandom;
        Data.cbData = cbClientRandom;
        CryptSetKeyParam(hMasterKey, KP_CLIENT_RANDOM,
                         (PBYTE)&Data, 0);

        // Specify server_random.
        Data.pbData = pServerRandom;
        Data.cbData = cbServerRandom;
        CryptSetKeyParam(hMasterKey, KP_SERVER_RANDOM,
                         (PBYTE)&Data, 0);
}

// Create the master hash object from the master key.
CryptCreateHash(hProv, CALG_SCHANNEL_MASTER_HASH,
                hMasterKey, 0, &hMasterHash);

// Derive read key from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_ENC_KEY,
               hMasterHash,
               fClient ? CRYPT_SERVER : 0,
               &hReadKey);

// Derive write key from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_ENC_KEY,
               hMasterHash,
               fClient ? 0 : CRYPT_SERVER,
               &hWriteKey);

if(<protocol being used> != <SSL 2.0>)
{
    // Derive read MAC from the master hash object.
    CryptDeriveKey(hProv,
                   CALG_SCHANNEL_MAC_KEY,
                   hMasterHash,
                   fClient ? CRYPT_SERVER : 0,
                   &hReadMAC);

    // Derive write MAC from the master hash object.
    CryptDeriveKey(hProv,
                   CALG_SCHANNEL_MAC_KEY,
                   hMasterHash,
                   fClient ? 0 : CRYPT_SERVER,
                   &hWriteMAC);
}

CryptDestroyHash(hMasterHash);


Finish Messages (TLS 1.0)

A "finished" message is always sent immediately after a "change cipher spec" message to verify that the key exchange and authentication processes were successful. The "finish" messages in the TLS 1.0 protocol are calculated using the Pseudo-Random Function (PRF) function with the input being the master key, a label, and a seed. The PRF uses the key, the label, and the seed as input and produces an output of arbitrary length. The following method is used to generate the PRF output used in TLS 1.0 "finish" messages.

A PRF hash handle is generated using CryptCreateHash with the ALG_ID value CALG_TLS1PRF and the handle to the master key is passed in the hKey parameter. The label and seed values are set on the hash handle using the values HP_TLS1PRF_LABEL and HP_TLS1PRF_SEED respectively in the dwParam parameter with the CryptSetHashParam function. Finally the protocol engine will call the function CryptGetHashParam with the value HP_HASHVAL in the dwParam parameter to retrieve the PRF data to be included in the finish message. When making the call to CryptGetHashParam, the protocol engine must specify how many bytes of data that the PRF function will produce. This is done in the pdwDataLen parameter, and the resulting data is placed in the buffer pointed to by the pbData parameter.

The protocol engine's source code is typically;

CRYPT_DATA_BLOB Data;
HCRYPTHASH hFinishHash;
BYTE rgbFinishPRF[12];
BYTE rgbCliHashOfHandshakes[36];

// get client finish message
CryptCreateHash(hProv, CALG_TLS1PRF, hMasterKey, 0, &hFinishHash);

Data.pbData = (BYTE*)"client finished";
Data.cbData = 15;
CryptSetHashParam(hFinishHash, HP_TLS1PRF_LABEL, (BYTE*)&Data, 0);

Data.pbData = rgbCliHashOfHandshakes;
Data.cbData = sizeof(rgbCliHashOfHandshakes);
CryptSetHashParam(hFinishHash, HP_TLS1PRF_SEED, (BYTE*)&Data, 0);

cbFinishPRF = sizeof(rgbFinishPRF);
CryptGetHashParam(hFinishHash, HP_HASHVAL, rgbFinishPRF, &cbFinishPRF, 0);

CryptDestroyHash(hFinishHash);


Bulk Data Encryption

The MAC is generated by hashing one of the MAC keys (via CryptHashSessionKey) together with the message contents and other data. The message is encrypted/decrypted with one of the bulk encryption keys in the usual manner.

When using a block cipher, the protocol engine does all necessary block cipher padding. When CryptEncrypt and CryptDecrypt are called, the Final flag is always FALSE and the data length is a whole multiple of blocks.

Note The CSP must never buffer data internally. Once the data has been encrypted (or decrypted), the size of the plaintext must always exactly match the size of the ciphertext.


Crossing Process Boundaries

The protocol engine (schannel.dll), in Windows NT® 5.0, performs the handshaking and authentication in a secure process and the bulk encryption/message passing in a different application process. This means that the bulk encryption and MAC keys need to be copied from one process to another. To do this, use the CryptExportKey and CryptImportKey functions as follows:

  1. The secure process exports each key into an OPAQUEBLOB using CryptExportKey. The CRYPT_DESTROYKEY flag will typically be specified so that the CSP will destroy the original key.
  2. The secure process passes the OPAQUEBLOBs to the application process, in a manner that is beyond the scope of this document.
  3. The application process imports each OPAQUEBLOB back into the CSP using CryptImportKey. At this point, the key is in exactly the same state as when it was exported.


The Opaque Blob Type

Opaque blobs (also known as OPAQUEBLOBs) are used to store session keys. They don't merely contain the base key material though, they also contain all of the current state information. This includes information such as the salt, the initialization vector, the key table, etc. Opaque blobs are called "opaque" because their format is unpublished. Each CSP vendor determines their own format, which should include encrypting the opaque blobs with some sort of symmetric key.

Once a key has been exported into an opaque blob, it can only be imported back into the same CSP from which it was originally exported.

When two processes are involved, each independently calls CryptAcquireContext, such that they both end up with a handle to a key container, possibly the same container. One process creates the keys and exports them into opaque blobs, then passes them to a second process, which imports them again.

If the CSP uses a hardware token that doesn't support exporting keys, then the blob may only contain the index of a key register, or something similar. In this case, the hardware can remain unaware of the whole procedure.

When the CRYPT_DESTROYKEY flag is passed into the CryptExportKey function, the original key is automatically destroyed by the CSP. For a hardware CSP, the handle to the original key is destroyed. This avoids the necessity of calling CryptDestroyKey on the original key, which may confuse some hardware CSPs by causing them to delete a key that you are still planning to use.

<secure process>
cbBlob = sizeof(rgbBlob);
CryptExportKey(hKey, 0, OPAQUEBLOB, CRYPT_DESTROYKEY,
               rgbBlob, &cbBlob);
hKey = 0;

<blob is transferred to other process>

<user process>
CryptImportKey(hProv, pbBlob, cbBlob, 0, 0, &hKey);


RSA/Schannel CSP Reference

This section lists each function that must be exported from the CSP, and briefly discusses any required functionality beyond PROV_RSA_FULL. Additional functions specific to the CSP may exist within the CSP.

Function | Description
CPAcquireContext | Acquires a handle to a particular key container within a particular CSP. See CPAcquireContext.
CPCreateHash | Initiates hashing a stream of data. See CPCreateHash Schannel Extensions.
CPDecrypt | Decrypts data that was previously encrypted via the CPEncrypt function. See CPDecrypt Schannel Extensions.
CPDeriveKey | Generates cryptographic keys derived from base data. See CPDeriveKey Schannel Extensions.
CPDestroyHash | Destroys the hash object referenced by the hHash parameter. See CPDestroyHash.
CPDestroyKey | Releases the handle referenced by the hKey parameter. After a key handle has been released, it becomes invalid and cannot be used again. See CPDestroyKey.
CPDuplicateHash | Makes an exact copy of a hash and the state the hash is in. See CPDuplicateHash.
CPDuplicateKey | Makes an exact copy of a key and the state the key is in. See CPDuplicateKey.
CPEncrypt | Encrypts data. See CPEncrypt Schannel Extensions.
CPExportKey | Exports cryptographic keys out of a cryptographic service provider in a secure manner. See CPExportKey Schannel Extensions.
CPGenKey | Generates random cryptographic keys for use with the CSP module. See CPGenKey Schannel Extensions.
CPGenRandom | Fills a buffer with random bytes. See CPGenRandom.
CPGetHashParam | Retrieves data that governs the operations of a hash object. See CPGetHashParam.
CPGetKeyParam | Retrieves data that governs the operations of a key. See CPGetKeyParam
CPGetProvParam | Retrieves parameters that govern the operations of a CSP. See CPGetProvParam Schannel Extensions.
CPGetUserKey | Retrieves a handle to a permanent user key pair, such as the user's signature key pair. See CPGetUserKey
CPHashData | Computes the cryptographic hash on a stream of data. See CPHashData.
CPHashSessionKey | Computes the cryptographic hash on a key object. See CPHashSessionKey Schannel Extensions.
CPImportKey | Transfers a cryptographic key from a key blob to a CSP. See CPImportKey Schannel Extensions.
CPReleaseContext | Releases a handle to a CSP and a key container. See CPReleaseContext.
CPSetHashParam | Customizes the operations of a hash object. Currently, only a single parameter is defined for this function. See CPSetHashParam.
CPSetKeyParam | Customizes various aspects of a key's operations. See CPSetKeyParam Schannel Extensions.
CPSetProvParam | Customizes the operations of a CSP. See CPSetProvParam.
CPSignHash | Signs a piece of data. See CPSignHash.
CPVerifySignature | Verifies a signature against a hash object. See CPVerifySignature.


CPCreateHash Schannel Extensions

Same as PROV_RSA_FULL except for the addition of the following hash algorithms:

CALG_SSL3_SHAMD5

CALG_SCHANNEL_MASTER_HASH

See CPCreateHash.


CALG_SSL3_SHAMD5

This functionality should be implemented in the same way as the Microsoft Base Cryptographic Provider. This implementation is described in some detail in the The SHA/MD5 RSA Signature Type section.


CALG_SCHANNEL_MASTER_HASH

The master hash is created from the master key just prior to deriving the bulk encryption keys, via a call to CPCreateHash:

CPCreateHash(hProv, CALG_SCHANNEL_MASTER_HASH,
             hMasterKey, 0, &hMasterHash);

The master hash should not maintain a reference to the master key. All relevant data associated with the master key should be copied over to the master hash object.

Depending on the protocol, the CSP should perform the following operations within the CPCreateHash function.

PCT1

All key derivation operations are done within the CPDeriveKey function.

SSL2

The "key block" from which the session keys are created should probably be created within this function. This key block is later used to create the respective session keys by the CPDeriveKey function. See the SSL 2 specification for a description of this key generation.

SSL 3.0

The key generated via CPGenKey (or CPImportKey) is not the master key, but a "pre-master key." See the SSL 3.0 specification. The "pre-master key" is used to generate the master key, via the following formula:

master_secret =
       MD5(pre_master_secret + SHA('A' + pre_master_secret +
           ClientHello.random + ServerHello.random)) +
       MD5(pre_master_secret + SHA('BB' + pre_master_secret +
           ClientHello.random + ServerHello.random)) +
       MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
           ClientHello.random + ServerHello.random));

Note The master key, not the "pre-master key," is hashed via CPHashSessionKey.

The "key block" from which the session keys are created should probably be created within this function. This key block is later used to create the respective session keys by the CPDeriveKey function. For details, see the SSL 3.0 specification. This is done via the following formula:

key_block =
       MD5(master_secret + SHA('A' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) +
       MD5(master_secret + SHA('BB' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) +
       MD5(master_secret + SHA('CCC' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) + [...];

TLS 1.0

The key generated via CPGenKey (or CPImportKey) is not the master key, but a "pre-master key." See the TLS 1.0 specification. The "pre-master key" is used to generate the master key, via the following formula:

master_secret = PRF(pre_master_secret, "master secret",
              ClientHello.random + ServerHello.random) [0..47];

The "key block" from which the session keys are created should probably be created within this function. This key block is later used to create the respective session keys by the CPDeriveKey function. This is done via the following formula:

key_block = PRF(SecurityParameters.master_secret,
                         "key expansion",
                         SecurityParameters.server_random +
                         SecurityParameters.client_random);


CPDecrypt Schannel Extensions

Same as PROV_RSA_FULL, except as noted in the Bulk Data Encryption section.

See CPDecrypt.


CPDeriveKey Schannel Extensions

The bulk encryption and MAC keys are derived from the master hash object (see CPCreateHash for a description of the master hash object). This is done using the CPDeriveKey function with either the CALG_SCHANNEL_ENC_KEY or the CALG_SCHANNEL_MAC_KEY algorithm identifier.

See CPDeriveKey.

If the CRYPT_SERVER flag is set in the dwFlags parameter then the key to be generated is a server write key, otherwise it is a client write key.

See the Deriving the Bulk Encryption and MAC Keys section.


CALG_SCHANNEL_ENC_KEY

Generate a bulk encryption key. The algorithm and key size have previously been specified via the CPSetKeyParam Schannel Extensions function.

Note that the initialization vector (IV) is typically set in the usual way (via CPSetKeyParam (KP_IV)). Some protocol and cipher suite combinations, however, insist on building the IV from the key block. In this case, the CSP should derive the IV automatically.

If SSL 2 is being used, then this key is also used as the MAC key.


CALG_SCHANNEL_MAC_KEY

Generate a MAC key. The algorithm has been previously been specified via the CPSetKeyParam Schannel Extensions function.


CPEncrypt Schannel Extensions

Same as PROV_RSA_FULL, except as noted in the Bulk Data Encryption section.

See CPEncrypt.


CPExportKey Schannel Extensions

Master keys can be exported into SIMPLEBLOBs. This should be implemented the same way as the export of normal bulk encryption keys, such as RC4 or DES. The aiKeyAlg field of the BLOBHEADER structure should be set to the algorithm identifier of the master key (CALG_PCT1_MASTER, CALG_SSL2_MASTER, CALG_SSL3_MASTER, or CALG_TLS1_MASTER).

If the CPExportKey function is used to export an SSL2 master key and the CRYPT_SSL2_FALLBACK flag is set, then the first 8 bytes of the encryption block padding should be set to 0x03 rather than to random data. This helps prevent version rollback attacks and is discussed in the SSL 3.0 specification.

If the CRYPT_DESTROYKEY flag is specified with the CPExportKey function, then the CSP should destroy the key (or the key handle) after exporting the key. This flag is intended for use only with opaque blobs. See the The Opaque Blob Type section.

See CPExportKey.


CPGenKey Schannel Extensions

Several new key types have been defined to represent master keys, one per supported protocol. These are discussed briefly in the Creating the Master Key section. The following sections provide more detail.

The CSP should create the master key material within the CPGenKey function.

CALG_PCT1_MASTER

CALG_SSL2_MASTER

CALG_SSL3_MASTER

CALG_TLS1_MASTER

See CPGenKey.


CALG_PCT1_MASTER

Master keys consist of 16 bytes of random data.


CALG_SSL2_MASTER

Master keys consist of 5 bytes of random data when an export cipher is used, and 16 bytes of random data when a domestic cipher is used.

When the CSP is domestic, it is not aware of the cipher suite when CPGenKey is called, thus the full 16 bytes should always be generated. If the cipher is an export cipher, 11 bytes of the master key can be overwritten by clear key data (within CPSetKeyParam). When the CSP is exportable, then it can only generate 5 bytes of data and will expect clear key data to be set with CPSetKeyParam.


CALG_SSL3_MASTER

Master keys consist of 48 bytes of data, with the SSL version number in the first two bytes and random data in the rest.


CALG_TLS1_MASTER

Master keys consist of 48 bytes of data, with the protocol version number in the first two bytes and random data in the rest.


CPGetProvParam Schannel Extensions

The PP_ENUMALGS_EX parameter must be supported as described in the Enumerating the Supported Protocols section.

See CPGetProvParam.


CPHashSessionKey Schannel Extensions

Same as PROV_RSA_FULL, except that when the CRYPT_LITTLE_ENDIAN flag is set, the CSP is to hash the key in reverse order.

See CPHashSessionKey.


CPImportKey Schannel Extensions

Master keys can be imported into the CSP within SIMPLEBLOBs using CPImportKey. The handle returned by this function should be equivalent to the handle returned by CPGenKey when a master key is created.

See the CPGenKey and CPExportKey sections.

If CPImportKey is used to import an SSL2 master key and the CRYPT_SSL2_FALLBACK flag is set, the encryption block padding should be examined after the RSA decryption. If the first 8 bytes are all equal to 0x03 then an error such as NTE_BAD_VER should be returned. This helps prevent version rollback attacks and is discussed in the SSL3 specification.

See CPImportKey.


CPSetKeyParam Schannel Extensions

Several new parameters have been defined for use with CPSetKeyParam .

The following new parameters are only valid when used with a master key and may be set multiple times on the same master key. If set multiple times, discard the old value and retain the new value.

The following parameters have been added and can be passed in the dwParam paramater.

KP_SCHANNEL_ALG

KP_CLEAR_KEY

KP_CLIENT_RANDOM

KP_SERVER_RANDOM

KP_CERTIFICATE

See CPSetKeyParam.


KP_SCHANNEL_ALG

This parameter specifies the bulk encryption and MAC algorithms and key sizes that will later be derived from the master key. The use of this parameter is shown in the Specifying the Algorithms section.


KP_CLEAR_KEY

This parameter specifies the "clear key" data. The value is only used when generating an export encryption key and should be ignored if using a domestic cipher.

When using PCT, the clear key data ranges from 0 to 16 bytes. When using SSL 2, the clear key data will be either 0 or 11 bytes. This parameter is not used by SSL 3.0 or TLS 1.0.


KP_CLIENT_RANDOM

When using SSL 3.0 or TLS 1.0, this parameter specifies the "client random" data. When using PCT, it specifies the "challenge" data. In both cases, this data originates in the "ClientHello" message.

When using PCT, SSL 3.0, or TLS 1.0, this data is always 32 bytes long. This parameter is not used by SSL 2.


KP_SERVER_RANDOM

When using SSL 3.0 or TLS 1.0, this parameter specifies the "server random" data. When using PCT, it specifies the "connection id" data. In both cases, this data originates in the "ServerHello" message.

When using PCT, SSL 3.0, or TLS 1.0, this data is always 32 bytes long. This parameter is not used by SSL 2.


KP_CERTIFICATE

This parameter specifies the "server certificate" data, and is used only for PCT.

Unlike the parameters above, the length of certificate data is variable and may be quite large. As an optimization, this data may be freed after both client keys have been generated.


Diffie-Hellman/Schannel CSP Overview

This section defines the Diffie-Hellman/Schannel Cryptographic Service Provider (CSP) type and describes the functionality that must be supported in order to be compatible with future versions of the Microsoft cryptographic protocol engine (Schannel.dll).

The information presented in the following sections is intended for developers who plan to implement a compatible Diffie-Hellman/Schannel CSP. Readers should have a basic familiarity with Diffie-Hellman algorithms, Secure Socket Layer (SSL) Version 3.0 protocol, Transport Layer Security (TLS) Version 1.0, public-key cryptography, digital certificates, and the Microsoft CryptoAPI function set. Before proceeding, readers who are new to these topics are advised to read the SSL Protocol 3.0 and TLS Protocol 1.0 specifications, the CryptoAPI Programmers Guide and Reference, available in the Microsoft Platform SDK, and the references provided in the Overview section of that CryptoAPI material.

The code samples in the following sections are presented from the perspective of the Microsoft protocol engine. To write a compatible CSP the reader needs to understand the SSL 3.0 and TLS 1.0 specifications and combine that knowledge with an understanding of the protocol engine code as presented here.

This document does not describe how to perform signature portions of the protocols because those procedures are outlined in other documentation on the Microsoft RSA and DSS Providers.

Note that information on how to develop a RSA/Schannel CSP is provided in RSA/Schannel CSP Overview.


The Protocol Engine's Contexts (Diffie-Hellman)

The protocol engine will create one or more contexts via a call to CryptAcquireContext with the dwProvType parameter set to PROV_DH_SCHANNEL. The dwFlags parameter will usually have the CRYPT_VERIFYCONTEXT flag set. These contexts are used to perform key exchange operations as well as bulk encryption.

The DH keys used by Schannel are always ephemeral. Because the key pairs are ephemeral, the CRYPT_VOLATILE flag is usually specified when CryptGenKey is called to create it. This flag requests that the key pair not be written to permanent storage.


Enumerating the Supported Protocols (Diffie-Hellman)

The supported protocols and cipher suites can be determined by calling CryptGetProvParam with PP_ENUMALGS_EX. This works in a manner similar to the use of PP_ENUMALGS, but returns the following structure instead of the more limited one returned when using PP_ENUMALGS.

// protocol flags
#define CRYPT_FLAG_SSL3         0x0004
#define CRYPT_FLAG_TLS1         0x0008

typedef struct _PROV_ENUMALGS_EX
{
    ALG_ID    aiAlgid;
    DWORD     dwDefaultLen;
    DWORD     dwMinLen;
    DWORD     dwMaxLen;
    DWORD     dwProtocols;
    DWORD     dwNameLen;
    CHAR      szName[20];
    DWORD     dwLongNameLen;
    CHAR      szLongName[40];
} PROV_ENUMALGS_EX;

The following table shows the algorithm list that might be returned by a typical (domestic) PROV_DH_SCHANNEL CSP.

Algid | Min | Max | Protocols | Name
CALG_DH_EPHEM | 512 | 2048 | 0x000C | "DH_KEYX"
CALG_MD5 | 128 | 128 | 0x000C | "MD5"
CALG_SHA | 160 | 160 | 0x000C | "SHA"
CALG_RC4 | 40 | 128 | 0x000C | "RC4"
CALG_DES | 56 | 56 | 0x000C | "DES"

Before sending a ClientHello or ServerHello message, the protocol engine enumerates all of the algorithms and key sizes supported by the CSP and internally build a list of supported cipher suites.


Public/Private Key Pair Usage (Diffie-Hellman)

Only CALG_DH_EPHEM is supported in the discussions that follow. The certificates used contain normal RSA or DSS public keys.


Creating the Master Key (Diffie-Hellman)

The master key is a piece of data from which all other keys are derived. For the two protocols described in this document, SSL 3.0 and TLS 1.0, it is 48 bytes in length. The master key is created by performing a Diffie-Hellman key exchange.

The Client Side (Diffie-Hellman)

The Server Side (Diffie-Hellman)

Specifying the Algorithms (Diffie-Hellman)


The Client Side (Diffie-Hellman)

The protocol engine's client-side code is typically:

HCRYPTPROV hProv      = <protocol engine's key container>;
HCRYPTKEY  hClientDHKey;  // handle to the client's DH key
HCRYPTKEY  hMasterKey;
ALG_ID     Algid;
PBYTE      pbServerPub = <pointer to Server Public Key>;
DWORD      cbServerPub = <size of Server Public Key>;
BYTE       rgbServerBlob[<max blob size>];
DWORD      cbServerBlob;
PBYTE      pbG = <pointer to generator G from Server>;
DWORD      cbG = <size of generator G from Server>;
PBYTE      pbP = <pointer to prime P from Server>;
DWORD      cbP = <size of prime P from Server>;
CRYPT_DATA_BLOB Data;
BYTE       rgbClientPubBlob[size of the client public key blob];
DWORD      cbClientPubBlob;

// generate and set the parameters on the client DH key
CryptGenKey(hProv, CALG_DH_EPHEM, 0, &hClientDHKey);

Data.pbData = pbP;
Data.cbData = cbP;
CryptSetKeyParam(hClientDHKey, KP_P, (BYTE*)&Data, 0);

Data.pbData = pbG;
Data.cbData = cbG;
CryptSetKeyParam(hClientDHKey, KP_G, (BYTE*)&Data, 0);

// actually create the client private DH key
CryptSetKeyParam(hClientDHKey, KP_X, NULL, 0);

// Build PUBLICKEYBLOB around the server's public key
{
     BLOBHEADER *pBlobHeader = (BLOBHEADER *)rgbServerBlob;
     DHPUBKEY   *pDHPubKey   = (DHPUBKEY *)(pBlobHeader + 1);
     BYTE       *pData       = (BYTE *)(pDHPubKey + 1);

     pBlobHeader->bType    = PUBLICKEYBLOB;
     pBlobHeader->bVersion = CUR_BLOB_VERSION;
     pBlobHeader->reserved = 0;
     pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;

     pDHPubKey->magic = 0x31484400;
     pDHPubKey->bitlen = dwServerPub * 8;

     ReverseMemCopy(pData, pbServerPub, cbServerPub);
     cbServerBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) +
       cbServerPub;
}

// import the server's public key and get an agreed key
CryptImportKey(hProv, rgbServerBlob, cbServerBlob, hClientDHKey, 0,
   &hMasterKey);

// Select the master key type.
switch(<protocol being used>)
{
    case <SSL 3.0>:
        Algid = CALG_SSL3_MASTER;
        break;

    case <TLS 1.0>:
        Algid = CALG_TLS1_MASTER;
        break;
}

// Convert the agreed key to the appropriate master key
CryptSetKeyParam(hMasterKey, KP_ALGID, (BYTE*)&Algid, 0);

// Get the client Diffie-Hellman public key.
cbClientPubBlob = sizeof(rgbClientPubBlob);
CryptExportKey(hClientDHKey, 0, PUBLICKEYBLOB,
               0, rgbClientPubBlob, & cbClientPubBlob);

CryptDestroyKey(hClientDHKey);


The Server Side (Diffie-Hellman)

The protocol engine's server-side code is typically:

HCRYPTPROV hProv      = <protocol engine's key container>;
HCRYPTKEY  hServerDHKey;  // handle to the client's DH key
HCRYPTKEY  hMasterKey;
ALG_ID     Algid;
PBYTE      pbClientPub = <pointer to Client Public Key>;
DWORD      cbServerPub = <size of Client Public Key>;
BYTE       rgbClientBlob[<max blob size>];
DWORD      cbClientBlob = <size of the Client Key blob>;
CRYPT_DATA_BLOB Data;

// Build PUBLICKEYBLOB around the client's public key
{
     BLOBHEADER *pBlobHeader = (BLOBHEADER *)rgbClientBlob;
     DHPUBKEY   *pDHPubKey   = (DHPUBKEY *)(pBlobHeader + 1);
     BYTE       *pData       = (BYTE *)(pDHPubKey + 1);

     pBlobHeader->bType    = PUBLICKEYBLOB;
     pBlobHeader->bVersion = CUR_BLOB_VERSION;
     pBlobHeader->reserved = 0;
     pBlobHeader->aiKeyAlg = CALG_DH_EPHEM;

     pDHPubKey->magic = 0x31484400;
     pDHPubKey->bitlen = dwClientPub * 8;

     ReverseMemCopy(pData, pbClientPub, cbClientPub);
     cbClientBlob = sizeof(BLOBHEADER) + sizeof(DHPUBKEY) +
        cbClientPub;
}

// import the client's public key and get an agreed key
CryptImportKey(hProv, rgbClientBlob, cbClientBlob, hServerDHKey, 0,
   &hMasterKey);

// Select the master key type.
switch(<protocol being used>)
{
    case <SSL 3.0>:
        Algid = CALG_SSL3_MASTER;
        break;

    case <TLS 1.0>:
        Algid = CALG_TLS1_MASTER;
        break;
}

// Convert the agreed key to the appropriate master key
CryptSetKeyParam(hMasterKey, KP_ALGID, (BYTE*)&Algid, 0);


Specifying the Algorithms (Diffie-Hellman)

After the master key has been created (or imported), the protocol engine must inform the CSP of the type of bulk encryption and MAC keys that will be derived from the master key. The following code specifies the algorithms. The same code is used for both client and server.

typedef struct _SCHANNEL_ALG
{
    DWORD  dwUse;
    ALG_ID Algid;
    DWORD  cBits;
} SCHANNEL_ALG, *PSCHANNEL_ALG;

SCHANNEL_ALG Algorithm;

// Specify encryption algorithm.
Algorithm.dwUse = SCHANNEL_ENC_KEY;
Algorithm.Algid = CALG_RC4;    // or CALG_RC2, CALG_DES, etc.
Algorithm.cBits = 40;          // or 64, 128, 192, etc.
CryptSetKeyParam(hMasterKey, KP_SCHANNEL_ALG, (PBYTE)&Algorithm, 0);

// Specify hash algorithm.
Algorithm.dwUse = SCHANNEL_MAC_KEY;
Algorithm.Algid = CALG_MD5;    // or CALG_SHA, etc.
Algorithm.cBits = 128;         // or 160...
CryptSetKeyParam(hMasterKey, KP_SCHANNEL_ALG, (PBYTE)&Algorithm, 0);

Note The protocol engine should never specify algorithms and key sizes unless they are supported by the CSP. For more information, see Enumerating the Supported Protocols (Diffie-Hellman). Where unsupported algorithms or key sizes are specified, the CSP should fail and return the value NTE_BAD_DATA error code.


Deriving the Bulk Encryption and MAC Keys (Diffie-Hellman)

The bulk encryption and MAC keys are mostly derived from the master key but often include a number of other items, depending on the protocol and cipher suite used.

The process is the same for both client and server:

  1. The protocol engine calls CryptSetKeyParam on the master key one or more times, such that the CSP has all of the information necessary to build the keys.
  2. A hash object is created from the master key via CryptCreateHash. This step is necessary because it is not possible to derive CryptoAPI keys directly from other keys.
  3. The two bulk encryption keys and the two MAC keys are created from the "master hash" object, via four calls to CryptDeriveKey.

Note When performing SSL "reconnects," the protocol engine may perform the above procedure several times, using the same master key. This enables the client and server to have multiple (often simultaneous) connections, each using different bulk encryption and MAC keys, but without doing any Diffie-Hellman operations.

As with all CSPs, it is important that good thread-safe practices are used. Thread counts of several dozen are not unusual.

The protocol engine's source code is typically;

BOOL fClient = <are we a client?>;
CRYPT_DATA_BLOB Data;
HCRYPTHASH hMasterHash;

// Finish creating the master_secret.
switch(<protocol being used>)
{
    case <SSL 3.0>:
    case <TLS 1.0>:

        // Specify client_random.
        Data.pbData = pClientRandom;
        Data.cbData = cbClientRandom;
        CryptSetKeyParam(hMasterKey, KP_CLIENT_RANDOM,
                         (PBYTE)&Data, 0);

        // Specify server_random.
        Data.pbData = pServerRandom;
        Data.cbData = cbServerRandom;
        CryptSetKeyParam(hMasterKey, KP_SERVER_RANDOM,
                         (PBYTE)&Data, 0);
}

// Create the master hash object from the master key.
CryptCreateHash(hProv, CALG_SCHANNEL_MASTER_HASH,
                hMasterKey, 0, &hMasterHash);

// Derive read key from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_ENC_KEY,
               hMasterHash,
               fClient ? CRYPT_SERVER : 0,
               &hReadKey);

// Derive write key from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_ENC_KEY,
               hMasterHash,
               fClient ? 0 : CRYPT_SERVER,
               &hWriteKey);

// Derive read MAC from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_MAC_KEY,
               hMasterHash,
               fClient ? CRYPT_SERVER : 0,
               &hReadMAC);

// Derive write MAC from the master hash object.
CryptDeriveKey(hProv,
               CALG_SCHANNEL_MAC_KEY,
               hMasterHash,
               fClient ? 0 : CRYPT_SERVER,
               &hWriteMAC);

CryptDestroyHash(hMasterHash);


Finish Messages (TLS 1.0) (Diffie-Hellman)

A "finished" message is always sent immediately after a "change cipher spec" message to verify that the key exchange and authentication processes were successful. The "finish" messages in the TLS 1.0 protocol are calculated using the Pseudo-Random Function (PRF) function with the input being the master key, a label, and a seed. The PRF uses the key, the label, and the seed as input and produces an output of arbitrary length. The following method is used to generate the PRF output used in TLS 1.0 "finish" messages.

A PRF hash handle is generated using CryptCreateHash with the ALG_ID value CALG_TLS1PRF and the handle to the master key is passed in the hKey parameter. The label and seed values are set on the hash handle using the values HP_TLS1PRF_LABEL and HP_TLS1PRF_SEED respectively in the dwParam parameter with the CryptSetHashParam function. Finally the protocol engine is to call the function CryptGetHashParam with the value HP_HASHVAL in the dwParam parameter to retrieve the PRF data to be included in the "finish" message. When making the call to CryptGetHashParam the protocol engine must specify how many bytes of data is to be output from the PRF function. This is done in the pdwDataLen parameter, and the resulting data is placed in the buffer pointed to by the pbData parameter.

The protocol engine's source code is typically;

CRYPT_DATA_BLOB Data;
HCRYPTHASH hFinishHash;
BYTE rgbFinishPRF[12];
BYTE rgbCliHashOfHandshakes[36];

// get client finish message
CryptCreateHash(hProv, CALG_TLS1PRF, hMasterKey, 0, &hFinishHash);

Data.pbData = (BYTE*)"client finished";
Data.cbData = 15;
CryptSetHashParam(hFinishHash, HP_TLS1PRF_LABEL, (BYTE*)&Data, 0);

Data.pbData = rgbCliHashOfHandshakes;
Data.cbData = sizeof(rgbCliHashOfHandshakes);
CryptSetHashParam(hFinishHash, HP_TLS1PRF_SEED, (BYTE*)&Data, 0);

cbFinishPRF = sizeof(rgbFinishPRF);
CryptGetHashParam(hFinishHash, HP_HASHVAL, rgbFinishPRF, &cbFinishPRF, 0);

CryptDestroyHash(hFinishHash);


Bulk Data Encryption (Diffie-Hellman)

The MAC is generated by hashing one of the MAC keys (via CryptHashSessionKey) together with the message contents and other data. The message is encrypted/decrypted with one of the bulk encryption keys in the usual manner.

When using a block cipher, the protocol engine does all necessary block cipher padding. When CryptEncrypt and CryptDecrypt are called, the Final flag is always FALSE and the data length a whole multiple of blocks.

Note The CSP must never buffer data internally. Once the data has been encrypted (or decrypted), the size of the plaintext must always exactly match the size of the ciphertext.


Crossing Process Boundaries (Diffie-Hellman)

The protocol engine (schannel.dll) in Windows NT® Version 5.0, performs the handshaking and authentication in a secure process and the bulk encryption/message passing in a different application process. This means that the bulk encryption and MAC keys need to be copied from one process to another. To do this, use CryptExportKey and CryptImportKey as follows:

  1. The secure process exports each key into an OPAQUEBLOB using CryptExportKey. The CRYPT_DESTROYKEY flag will typically be specified so that the CSP will destroy the original key.
  2. The secure process passes the OPAQUEBLOBs to the application process in a manner that is beyond the scope of this document.
  3. The application process imports each OPAQUEBLOB back into the CSP using CryptImportKey. At this point, the key is in exactly the same state as when it was exported.


The Opaque Blob Type (Diffie-Hellman)

Opaque blobs (also known as OPAQUEBLOBs) are used to store session keys. They don't merely contain the base key material though, they also contain all of the current state information. This includes information such as the salt, the initialization vector, the key table, etc. Opaque blobs are called "opaque" because their format is unpublished. Each CSP vendor determines their own format, which should include encrypting the Opaque Blobs with some sort of symmetric key.

Once a key has been exported into an opaque blob, it can only be imported back into the same CSP from which it was originally exported.

When two processes are involved, each independently calls CryptAcquireContext, such that they both end up with a handle to a key container, possibly the same container. One process creates the keys and exports them into opaque blobs, then passes them to the second process, which imports them again.

If the CSP uses a hardware token that doesn't support exporting keys, then the blob may only contain the index of a key register, or something similar. In this case, the hardware can remain unaware of the whole procedure.

When the CRYPT_DESTROYKEY flag is passed into the CryptExportKey function, the original key is automatically destroyed by the CSP. For a hardware CSP, the handle to the original key is destroyed. This avoids the necessity of calling CryptDestroyKey on the original key, which may confuse some hardware CSPs by causing them to delete a key that you are still planning to use.

<secure process>
cbBlob = sizeof(rgbBlob);
CryptExportKey(hKey, 0, OPAQUEBLOB, CRYPT_DESTROYKEY,
               rgbBlob, &cbBlob);
hKey = 0;

<blob is transferred to other process>

<user process>
CryptImportKey(hProv, pbBlob, cbBlob, 0, 0, &hKey);


Diffie-Hellman/Schannel CSP Reference

This section lists each function that must be exported from the CSP, and briefly discusses any required functionality beyond PROV_DSS_DH. Additional functions specific to a CSP may exist within the CSP.

Function | Description
CPAcquireContext | Acquires a handle to a particular key container within a particular CSP. See CPAcquireContext.
CPCreateHash | Initiates hashing a stream of data. See CPCreateHash Diffie-Hellman/Schannel Extensions.
CPDecrypt | Decrypts data that was previously encrypted via the CPEncrypt function. See CPDecrypt Diffie-Hellman/Schannel Extensions.
CPDeriveKey | Generates cryptographic keys derived from base data. See CPDeriveKey Diffie-Hellman/Schannel Extensions.
CPDestroyHash | Destroys the hash object referenced by the hHash parameter. See CPDestroyHash.
CPDestroyKey | Releases the handle referenced by the hKey parameter. After a key handle has been released, it becomes invalid and cannot be used again. See CPDestroyKey.
CPDuplicateHash | Makes an exact copy of a hash and the state the hash is in. See CPDuplicateHash.
CPDuplicateKey | Makes an exact copy of a key and the state the key is in. See CPDuplicateKey.
CPEncrypt | Encrypts data. See CPEncrypt Diffie-Hellman/Schannel Extensions.
CPExportKey | Exports cryptographic keys from a cryptographic service provider in a secure manner. See CPExportKey.
CPGenKey | Generates random cryptographic keys for use with the CSP module. See CPGenKey.
CPGenRandom | Fills a buffer with random bytes. See CPGenRandom.
CPGetHashParam | Retrieves data that governs the operations of a hash object. See CPGetHashParam.
CPGetKeyParam | Retrieves data that governs the operations of a key. See CPGetKeyParam.
CPGetProvParam | Retrieves parameters that govern the operations of a CSP. See CPGetProvParam Diffie-Hellman/Schannel Extensions.
CPGetUserKey | Retrieves a handle to a permanent user key pair, such as the user's signature key pair. See CPGetUserKey.
CPHashData | Computes the cryptographic hash on a stream of data. See CPHashData.
CPHashSessionKey | Computes the cryptographic hash on a key object. See CPHashSessionKey Diffie-Hellman/Schannel Extensions.
CPImportKey | Transfers a cryptographic key from a key blob to a CSP. See CPImportKey.
CPReleaseContext | Releases a handle to a CSP and a key container. See CPReleaseContext.
CPSetHashParam | Customizes the operations of a hash object. Currently, only a single parameter is defined for this function. See CPSetHashParam.
CPSetKeyParam | Customizes various aspects of a key's operations. See CPSetKeyParam Diffie-Hellman/Schannel Extensions.
CPSetProvParam | Customizes the operations of a CSP. See CPSetProvParam.
CPSignHash | Signs a piece of data. See CPSignHash.
CPVerifySignature | Verifies a signature against a hash object. See CPVerifySignature.


CPCreateHash Diffie-Hellman/Schannel Extensions

Same as PROV_DSS_DH except for the addition of the following hash algorithm;

CALG_SCHANNEL_MASTER_HASH (Diffie-Hellman)

See CPCreateHash.


CALG_SCHANNEL_MASTER_HASH (Diffie-Hellman)

The master hash is created from the master key just prior to deriving the bulk encryption keys, via a call to CPCreateHash:

CPCreateHash(hProv, CALG_SCHANNEL_MASTER_HASH,
             hMasterKey, 0, &hMasterHash);

The master hash should not maintain a reference to the master key. All relevant data associated with the master key should be copied to the master hash object.

Depending on the protocol, the CSP should perform the following operations within CPCreateHash.

SSL 3.0

The key generated via CPGenKey (or CPImportKey) is not the master key, but a "pre-master key". The "pre-master key" is used to generate the master key, via the following formula (See the SSL 3.0 specification);

Note that the master key, not the "pre-master key" is hashed via CPHashSessionKey.

master_secret =
       MD5(pre_master_secret + SHA('A' + pre_master_secret +
           ClientHello.random + ServerHello.random)) +
       MD5(pre_master_secret + SHA('BB' + pre_master_secret +
           ClientHello.random + ServerHello.random)) +
       MD5(pre_master_secret + SHA('CCC' + pre_master_secret +
           ClientHello.random + ServerHello.random));

The "key block" from which the session keys are created should probably be created within this function. This key block is later used to create the respective session keys by CPDeriveKey fcalls. This is done via the following formula;

key_block =
       MD5(master_secret + SHA('A' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) +
       MD5(master_secret + SHA('BB' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) +
       MD5(master_secret + SHA('CCC' + master_secret +
                               ServerHello.random +
                               ClientHello.random)) + [...];

TLS 1.0

The key generated via CPGenKey (or CPImportKey) is not the master key, but a "pre-master key". The "pre-master key" is used to generate the master key, via the following formula (See the TLS 1.0 specification);

master_secret = PRF(pre_master_secret, "master secret",
              ClientHello.random + ServerHello.random) [0..47];

The "key block" from which the session keys are created should probably be created within this function. This key block is later used to create the respective session keys by the CPDeriveKey function. This is done via the following formula;

key_block = PRF(SecurityParameters.master_secret,
                         "key expansion",
                         SecurityParameters.server_random +
                         SecurityParameters.client_random);


CPDecrypt Diffie-Hellman/Schannel Extensions

Same as PROV_DSS_DH, except as noted in the Bulk Data Encryption (Diffie-Hellman) section.

See CPDecrypt.


CPDeriveKey Diffie-Hellman/Schannel Extensions

The bulk encryption and MAC keys are derived from the master hash object (see CPCreateHash for a description of the master hash object). This is done using CPDeriveKey with either the CALG_SCHANNEL_ENC_KEY (Diffie-Hellman) or the CALG_SCHANNEL_MAC_KEY (Diffie-Hellman) algorithm identifier.

See CPDeriveKey.

If the CRYPT_SERVER flag is set in the dwFlags parameter then the key to be generated is a server write key, otherwise it's a client write key.

See the Deriving the Bulk Encryption and MAC Keys (Diffie-Hellman) section.


CALG_SCHANNEL_ENC_KEY (Diffie-Hellman)

Generate a bulk encryption key. The algorithm and key size have previously been specified via CPSetKeyParam Diffie-Hellman/Schannel Extensions.

The CSP should create the initialization vector (IV) automatically.


CALG_SCHANNEL_MAC_KEY (Diffie-Hellman)

Generate a MAC key. The algorithm has been previously been specified via CPSetKeyParam Diffie-Hellman/Schannel Extensions.


CPEncrypt Diffie-Hellman/Schannel Extensions

Same as PROV_DSS_DH, except as noted in the Bulk Data Encryption (Diffie-Hellman) section.

See CPEncrypt.


CPGetProvParam Diffie-Hellman/Schannel Extensions

The PP_ENUMALGS_EX parameter must be supported as described in the Enumerating the Supported Protocols (Diffie-Hellman) section.

See CPGetProvParam.


CPHashSessionKey Diffie-Hellman/Schannel Extensions

Same as PROV_DSS_DH, except that when the CRYPT_LITTLE_ENDIAN flag is set, the CSP is to hash the key in reverse order.

See CPHashSessionKey.


CPSetKeyParam Diffie-Hellman/Schannel Extensions

Several new parameters have been defined for use with CPSetKeyParam.

The following new parameters are only valid when used with a master key and may be set multiple times on the same master key. If set multiple times, discard the old value and retain the new value.

The following parameters have been added and can be passed in the dwParam parameter.

KP_SCHANNEL_ALG (Diffie-Hellman)

KP_CLIENT_RANDOM (Diffie-Hellman)

KP_SERVER_RANDOM (Diffie-Hellman)

KP_ALGID (Diffie-Hellman)

See CPSetKeyParam.


KP_SCHANNEL_ALG (Diffie-Hellman)

This parameter is used to specify the bulk encryption, MAC algorithms, and key sizes that will be derived from the master key. The use of this parameter is shown in the Specifying the Algorithms (Diffie-Hellman) section.


KP_CLIENT_RANDOM (Diffie-Hellman)

This parameter is used to specify the "client random" data and is 32 bytes long.


KP_SERVER_RANDOM (Diffie-Hellman)

This parameter is used to specify the "server random" data and is 32 bytes long.


KP_ALGID (Diffie-Hellman)

This parameter is used to change the key from an agreed key to the required pre-master secret key. Two new algorithm types have been added for use with this value, CALG_SSL3_MASTER and CALG_TLS1_MASTER.

For more information on pre-master secret keys, see CALG_SCHANNEL_MASTER_HASH (Diffie-Hellman).


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

Remedy: Insert the MSDN Library CD into the CD-ROM drive.