Microsoft Internet Explorer 3.0 Signature and Certificate Interface: Application Programmer's Guide and Reference

Beta Release

September 10, 1996

(Preliminary)

Microsoft Corporation

Contents

Overview

Data Integrity Through Digital Signatures
Entity Authentication Through Certificates
The Hierarchy of Trust
Digital Certification
Overview of Related Standards
X.509 Certificates
X.500 Names
PKCS #7 Signed Data Signature Blocks
PKCS #10 Certification Request

The COM Interface Suite

Component Classes

Certificates
Certificate Store
Certificate Requests
Signature Blocks

Important Interfaces

IAmHashed
IAmSigned
ICertificateList
ICertificateStore
ICertificateStoreAux
ICertificateStoreRegInit
IPkcs7SignedData
IPkcs10
IPublicKeyContainer
IPublicKeyPair
ISelectedAttributes
ISignableDocument
ISignerInfo
IX509
IX500Name

This document describes a suite of COM interfaces that manipulate objects relating to the technical infrastructure needed to support the affixing of "digital signatures" to data of various forms and, subsequently, to verify that a given signature is correct and is acceptable.

Overview

Secure communications over nonsecure networks generally involves three major areas of concern—privacy, authentication, and data integrity.

Privacy indicates the desire to keep anyone except the intended recipient from being able to read the message. Accomplishing this usually involves some type of data encryption and decryption, otherwise known as cryptography.

Authentication is the need to know that the entity with whom you are communicating is, in fact, who you think it is. Perhaps the most common method of accomplishing this is through the use of certificates. A certificate is a set of data that identifies an entity and verifies that the specific public encryption and signature keys belongs to that entity. A certificate is issued by a Certification Authority (CA) only after that authority has verified that the specified public key belongs to the specified entity.

Another concern in secure communications is data integrity—the process of insuring that the data has not been changed or modified while en route to its intended destination. Data integrity is usually accomplished through the use of digital signatures, the electronic equivalent of a written signature on a piece of paper.

The Microsoft® Internet Explorer version 3.0 Signature and Certificate Interface (IE3 Sig) addresses the concerns of authentication and of data integrity. Authentication is addressed through COM interfaces that provide for the processing and management of certificates, and data integrity is addressed through COM interfaces that provide for the processing of digital signatures.

Data Integrity Through Digital Signatures

Digital signatures are based on well-known cryptographic technologies known as public-key cryptography. To sign a document, the signer first produces a hash of the object using one of several well-known and well-studied cryptographic hash algorithms. Cryptographic hashes are typically large, on the order of sixteen to twenty bytes, and are believed to be secure in the sense that it is computationally unfeasible to find a document that hashes to a particular, given value. Cryptographic hash algorithms are sometimes also referred to as digest algorithms.

The signature of the document is then nothing more than the encryption of the document's hash. However, a special type of encryption algorithm is used, one where the key used to encrypt data is different than the key later used to decrypt it and, further, knowledge of one key doesn't help you figure out what the other one is. One key in such a pair is kept secret and is known as the private key. It's corresponding mate is broadly distributed and is called a public key.

The signature, then, is the encryption of the document's hash using a certain private key. The document and its signature are then together distributed to the appropriate recipients.

To verify the signature, the recipient computes the hash in two ways:

  1. From the document itself, just as the signer did.

  2. By decrypting the encrypted hash that he was given, using, of course, the appropriate public key.

If the two hashes match, the recipient can be assured that the contents of the document are in the same state as when they were signed and that they were signed by the person who has possession of the private key that corresponds to the public key used to decrypt the hash.

Entity Authentication Through Certificates

The use of some physical document to achieve authentication has been in existence for a long time. For example, when you write a check for some purchase 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 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 or, more often, just certificates. The use of certificates on a network is more complex because of the fact that the communicating parties will most likely never physically meet—necessitating that a method be worked out so that the necessary level of trust is still maintained. Additionally, on a network, it is much easier for unethical people to intercept messages and pretend to be someone that they are not. To prevent these kinds of problems, cryptographic techniques are used on the certificate to make it very difficult, if not impossible, for someone to modify it such that he or she can pose as 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.

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 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 then can certify other, first-tier CAs, who can then certify second-tier CAs, as shown in the following diagram.

Figure 1. The hierarchy of trust

When someone on the network receives a certificate that has been issued by a first- or second-tier CA, he or she can verify that the CA that signed the certificate has been certified by a CA at the tier above it and that, in turn, that CA has been certified by the one above it, and so on until a chain of trust exists between the lower level CA (or a user certificate) and the root CA. For example, in the preceding diagram, it can 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; in the real world the situation is rapidly evolving, with no single "root" authority having been established or accepted. It remains to be seen exactly how the actual situation will 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 a 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 only the CA and can, thereby, develop trust in Alice's public key.

The typical implementation of digital certification involves a signature algorithm for signing the certificate. The process may go as follows:

  1. Alice sends a signed certification request containing her name and her public key to a CA. The request must be signed by Alice to prove that she has the private key that coincides with the public key contained in the request.

  2. The CA creates a special message from Alice's request and signs it with its private key, obtaining a separate signature in the process. The CA returns the message and the signature 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 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 and without any secret information, that the certificate was signed by the CA.

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 is made available to users of the network so that they can determine the validity of any given certificate.

Overview of Related Standards

Quite a number of broadly used standards exist in the area of public key cryptography and digital signatures. Among these are:

X.509 Certificates

In order to provide context for what follows, a brief review of the contents of an X.509 certificate is presented. Note, though, that the X.509 certificate is only described to a degree sufficient for the understanding of this document; for detailed X.509 information, consult the ITU-T recommendation X.509 (also, ISO/IEC 9594-8). Be advised that IE3 Sig does not support the issuerUniqueIdentifier or subjectUniqueIdentifier fields.

The top-level ASN.1 for a certificate can be written as:

CertificateInfo ::= SEQUENCE {
   version          [0] Version DEFAULT v1,
   serialNumber     INTEGER,
   signature        AlgorithmIdentifier,
   issuer           Name,
   validity         Validity,
   subject          Name,
   subjectPublicKeyInfo       SubjectPublicKeyInfo,
   issuerUniqueIdentifier    [1]  IMPLICIT UniqueIdentifier OPTIONAL,-- If
                    present, version must be v2 or v3.
   SubjectUniqueIdentifier  [2]  IMPLICIT UniqueIdentifier OPTIONAL,-- If
                    present, version must be v2 or v3.
   Extensions          [3]  EXPLICIT Extensions OPTIONAL  -- If 
                    present, version must be v3.
   }
Validity ::= SEQUENCE {
   notBefore      UTCTIME,
   notAfter       UTCTIME
   }
Certificate ::= SEQUENCE {
   signedData      CertificateInfo,   -- The certificate 
                              information.
   AlgorithmIdentifier  AlgorithmIdentifier,   -- The hash and  
                              encryption 
                              algorithms used.
   EncryptedHash    BIT STRING   -- The encrypted hash of 
                              the certificate
                              information.
      }

This defines a sequence (in C it would be called a struct) CertificateInfo that contains some number of members: the name of the entity that issued this certificate, which, together with the issuer-assigned serial number uniquely identifies this certificate; the name of the subject of the certificate, the subject's public key information, the validity period for this certificate, and so on. A Certificate is then simply a CertificateInfo together with an encrypted hash along with an identification of the particular algorithms used.

There is a Name data type used for the subject and issuer names. This isn't an ordinary, simple data type, like a string. Rather, it's a complicated data construct defined by X500.2. Also, notice the extensions field in the CertificateInfo. The Extensions data type can be written as:

Extensions ::= SEQUENCE OF Extension
Extension ::= SEQUENCE {
   extnId     OBJECT IDENTIFIER,   -- identifies semantic of 
                              particular extension.
   Critical   BOOLEAN DEFAULT FALSE, -- if true, then if you  
                              don't understand this 
                              semantic of extension,
                              throw out the 
                              certificate.
   ExtnValue  OCTET STRING    -- The (arbitrary) data of 
                              the extension.
}

Inside the CertificateInfo of a Certificate there can be an arbitrary list of any number of extensions (including zero), each of which is completely arbitrary in format. An OBJECT IDENTIFIER is the method used by OSI to identify the semantic of a particular extension and is globally unique.

Anyone can make up a new certificate extension (and most people, it seems, do), therefore any interface or application programming interface (API) for manipulating certificates must allow for this in a reasonable way. That being said, there are a certain number of more or less standard and common extensions that might as well be considered part of the core content of a certificate.

X.500 Names

The following code is the ASN.1 representation of a Name:

Name ::= CHOICE { 
 rdnSequence RDNSequence   -- Only one possibility for now.
 }
RDNSequence   ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
AttributeTypeAndValue  ::= SEQUENCE {
 type  ATTRIBUTE.&ID,  -- ie: an OBJECT IDENTIFIER.
 value ATTRIBUTE.&Type  -- ie: data in arbitrary format per the 
          object identifier.
 }

C programmers can think of this as an "array of sets of tagged arbitrary blobs."

In practice, things are not quite this bad:

UniversalString is IS0646, the 4-byte generalization of Unicode; PrintableString is a subset of ASCII made up of letters, numbers, and limited punctuation; TeletexString is a monstrosity that is best ignored. DirectoryString isn't my favorite data type, but at least it allows for generality while still being compact in the common cases.

Some of these even have standard abbreviations, such as CN for "id-at-commonName," and OU for "id-at-organizationalUnitName."

Regrettably, while there is a limited standard for a string representation of an X.500 name, there is absolutely no standard, either de jure or de facto, for the semantics and meaning of each of the elements in the RDN Sequence. Some name-creating bodies, for example, use the "id-at-organizationName" where others use "id-at-organizationalUnitName;" some names use more than one organizational unit name, where others do not; and so on.

PKCS #7 Signed Data Signature Blocks

PKCS #7 defines the SignedData structure for the purpose of being able to affix one or more signatures to a chunk of data. The ASN.1 for a SignedData structure is specified by PKCS #7 as follows:

SignedData ::= SEQUENCE {
   version          Version,
   digestAlgorithms DigestAlgorithmIdentifiers,
   contentInfo      ContentInfo,
   certificates     [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
   crls             [1] IMPLICIT CertificateRevocationLists OPTIONAL,
   signerInfos      SignerInfos 
   }
DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
SignerInfos ::= SET OF SignerInfo

The following are relevant things to note:

SignerInfo is defined as follows:

SignerInfo ::= SEQUENCE {
   version                    Version,
   issuerAndSerialNumber      IssuerAndSerialNumber,
   digestAlgorithm             DigestAlgorithmIdentifier,
   authenticatedAttributes    [0] IMPLICIT Attributes OPTIONAL,
   digestEncryptionAlgorithm  DigestEncryptionAlgorithmIdentifier,
   encryptedDigest            EncryptedDigest,
   unauthenticatedAttributes  [1] IMPLICIT Attributes OPTIONAL 
   }
IssuerAndSerialNumber  := SEQUENCE {
   issuer                 Name,
   serialNumber           CertificateSerialNumber
   }
EncryptedDigest       ::= OCTET STRING
Attributes            ::= SET OF Attribute
Attribute             ::= SEQUENCE { 
   type               ATTRIBUTE.&id,  -- Another OBJECT IDENTIFIER
   values             SET OF ATTRIBUTE.&Type  -- Yet another blob per 
                           the object identifier.
   }

Of note, a SignerInfo has:

ContentInfo is defined by PCKS#7 as follows:

   CONTENTINFO ::= CLASS {
      &Type,
      &id               OBJECT IDENTIFIER UNIQUE 
      }
   WITH SYNTAX {
      WITH SYNTAX       &Type
      ID                &id 
      }
   ContentInfo ::= SEQUENCE {
      contentType       CONTENTINFO.&id,
      content           [0] EXPLICIT CONTENTINFO.&Type OPTIONAL
      }

A ContentInfo is yet another set of data that is parameterized by an object identifier. If you know the object identifier, you know how to process the data. PKCS #7 defines several ContentInfo data types, including:

data                      OBJECT IDENTIFIER ::= { pkcs-7 1 }
signedData                OBJECT IDENTIFIER ::= { pkcs-7 2 }
envelopedData             OBJECT IDENTIFIER ::= { pkcs-7 3 }
signedAndEnvelopedData    OBJECT IDENTIFIER ::= { pkcs-7 4 }
digestedData              OBJECT IDENTIFIER ::= { pkcs-7 5 }
encryptedData             OBJECT IDENTIFIER ::= { pkcs-7 6 }

The Data field represents data, the definition of which lies outside of any ASN.1; its data format is OCTET STRING so far as ASN.1 is concerned. SignedData has data as discussed previously. The remaining types allow for various cryptographic operations that go beyond merely signing things to include such things as encryption. While very interesting indeed, they are beyond the scope of the present document and are not supported in IE3 Sig.

As was noted previously, the design presented in PKCS #7 has the actual content contained physically inside ContentInfo. If you want to sign something, you have to, in effect, change its file format to be a SignedData or a ContentInfo that contains a SignedData. Since this is not practical in the real world, a means of referring, in ContentInfo, to an external data source has been defined. To accomplish this, a new ContentInfo type has been invented, called IndirectDataContent. IndirectDataContent contains:

  1. An indication of the kind of data to be hashed. This is an object identifier; thus, new kinds of indirect data can be independently invented.

  2. Optionally, an indication of the actual data to be hashed. This is specified in a syntax governed by the object identifier. Commonly this is a file name, a Uniform Resource Locator (URL), or other type of data, along with any additional parameters needed to indicate which specific subpart of the data is involved. If this indication is absent, then the actual data to be hashed is located implicitly in an object-identifier–specific means, such as the file in which the IndirectDataContent is physically located. For Java .class files, this indication is typically omitted, meaning that the indicated data is the containing .class file.

  3. A digest of the indicated data, along with an indication of the digest algorithm used. This digest/digest-algorithm pair is then itself digested and signed as part of the signing process of the SignedData per PKCS#7—thus, associating a digital signature with the indicated data.

The definition of IndirectDataContent and related structures is as follows:

   
indirectDataContent CONTENTINFO ::= {
       WITH SYNTAX      IndirectDataContent
       ID              id-indirectdata
      }
   IndirectDataContent ::= SEQUENCE {
      data             AttributeTypeAndOptionalValue,
      messageDigest      DigestInfo          -- DigestInfo is defined in PKCS #1
      }
   AttributeTypeAndOptionalValue ::= SEQUENCE {
      type               ATTRIBUTE.&id,
      value            ATTRIBUTE.&Type({...}{@type}) OPTIONAL
      }
   id-indirectdata OBJECT IDENTIFIER ::= (value to be supplied)

Remember that in practice this is contained inside a ContentInfo, which is contained inside a SignedData, which may in turn be contained inside another ContentInfo. An example of an IndirectDataContent that has been defined is:

rawFileSourceType ATTRIBUTE   ::=   {
   WITH SYNTAX            RawFileData
   ID                     id-indirectdata-rawFile
      }
RawFileData ::= Link

A Link just names an external reference; it is a generalization of an URL and moniker. For completeness, its definition is as follows:

Link ::= CHOICE {
   url             [0] IMPLICIT UniformResourceLocator,
   moniker         [1] IMPLICIT SerializedMoniker,
   file            [2] IMPLICIT FileName
   } 
UniformResourceLocator ::= IA5String
FileName               ::= DcmiString
SerializedMoniker      ::= SerializedObject
SerializedObject       ::= SEQUENCE {
   classid             Uuid,         
   serializedData      OCTET STRING -- format determined by classid
   }
Uuid       ::= OCTET STRING (SIZE(16..16))   -- an OSF UUID
DcmiString ::= CHOICE {
   unicode          [0] IMPLICIT BMPString,
   ascii            [1] IMPLICIT IA5String
   }

Put that altogether and you understand the data formats needed to affix a signature to a raw flat file.

PKCS #10 Certification Request

When an end entity (user) needs to get a certificate from a Certification Authority (CA), a request must be constructed following a carefully defined structure and format. Then this request is transmitted to the CA.

A certification request consists of a distinguished name, a public key, and an optional set of attributes, collectively signed by the entity (user) requesting certification. Certification requests are sent to a CA, who usually transforms the request to an X.509 public-key certificate (or possibly a PKCS #6 extended certificate. In what form the CA returns the newly signed certificate is outside the scope of this document.)

The intention of including a set of attributes is twofold: to provide other information about a given entity, such as the postal address to which the signed certificate should be returned if electronic mail is not available, or a "challenge password" by which the entity may later request certificate revocation; and to provide attributes for a PKCS #6 extended certificate. A nonexhaustive list of attributes is given in PKCS #9.

The primary intended application of this standard is to support PKCS #7 cryptographic messages.

A certification request consists of three parts: certification request information, a signature algorithm identifier, and a digital signature on the certification request information. The certification request information consists of the entity's distinguished name, the entity's public key, and a set of attributes providing other information about the entity.

The process by which a certification request is constructed involves the following steps:

  1. A CertificationRequestInfo value containing a distinguished name, a public key, and an optional set of attributes is constructed by an entity.

  2. The CertificationRequestInfo value is signed with the entity's private key.

  3. The CertificationRequestInfo value, a signature algorithm identifier, and the entity's signature are collected together into a CertificationRequest value, defined below.

A certification authority fulfills the request by verifying the entity's signature, and, if it is valid, constructing an X.509 certificate from the distinguished name and public key, issuer name, serial number, validity period, and signature algorithm of the CA's choice. If the certification request contains a PKCS #9 extended-certificate–attributes attribute, the CA also constructs a PKCS #6 extended certificate from the X.509 certificate and the extended-certificate–attributes attribute value.

Certification request information shall have ASN.1 type CertificationRequestInfo:

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

CertificationRequestInfo fields have the following meanings:

A certification request shall have ASN.1 type CertificationRequest:

CertificationRequest ::= SEQUENCE {
  certificationRequestInfo  CertificationRequestInfo,
  signatureAlgorithm        SignatureAlgorithmIdentifier,
  signature Signature }
SignatureAlgorithmIdentifier ::= AlgorithmIdentifier
Signature ::= BIT STRING

The CertificationRequest fields have the following meanings:

The signature process consists of two steps:

  1. The value of the certificationRequestInfo field is DER encoded, yielding an octet string.

  2. The result of step 1 is signed with the certification-request subject's private key under the specified signature algorithm, yielding a bit string—the signature.

The COM Interface Suite

The previous section gave you an introduction to data integrity through digital signatures and authentication through the use of certificates. It also introduced you to a number of standards that are used in secure communications.

This section will show you how those concepts and standards are implemented in the Microsoft Internet Explorer 3.0 Signature and Certificate Interface.

Component Classes

These are a suite of COM objects that expose interrelated interfaces through which data can be manipulated and actions can be taken. These objects can be grouped into four categories—certificates, certificate store, certificate requests, and signature blocks.

Certificates

The objects in this class have interfaces that can manipulate the data contained in an X.509 certificate. The objects and the interfaces they expose follow.

X509

      interface IUnknown;
      interface IPersistFile;
      interface IPersistStream;
      interface IPersistMemBlob;
      interface IX509;
      interface IAmHashed;
      interface IAmSigned;
      interface ISelectedAttributes;
      interface IPublicKeyContainer;
      interface IPublicKeyPair;

X500_Name

An X500_Name is a sequence of X500_RelativeDistinguishedNames.

      interface IUnknown;
      interface IPersistFile;
      interface IPersistStream;
      interface IPersistMemBlob;
      interface IX500Name;

X500_RelativeDistinguishedName

interface IUnknown;
      interface ISelectedAttributes;

Certificate objects relationships

Figure 2 shows the relationships between some of the certificate objects.

Figure 2. Certificate object interface relationships

Certificate Store

These objects deal with persistently storing and retrieving X.509 certificates.

CertificateStore

      interface IUnknown;
            interface ICertificateStore;
            interface ICertificateStoreRegInit;
            interface ICertificateStoreAux;
      interface ICertificateList;

Certificate store object interfaces

Figure 3 shows the most important interfaces for the CertificateStore object.

Figure 3. CertificateStore object interfaces

Certificate Requests

These objects are used to request a certificate from a CA.

Pkcs10

      interface IUnknown;
      interface IPersistFile;
      interface IPersistStream;
      interface IPersistMemBlob;
      interface IPkcs10;
      interface ISelectedAttributes;
      interface IAmHashed;
      interface IAmSigned;
      interface IPublicKeyContainer;
      interface IPublicKeyPair;

Pkcs10Subject

The same as X500_Name.

      interface IUnknown;
      interface IPersistFile;
      interface IPersistStream;
      interface IPersistMemBlob;
      interface IX500Name;

plus:

      interface ISelectedAttributes;   

Certificate request objects relationships

Figure 4 shows the relationships between some of the certificate request objects.

Figure 4. Request for certificate interface relationships

Signature Blocks

These objects provide the capability to sign data and verify signatures.

Pkcs7SignedData

      interface IUnknown;
      interface IPersistFile;
      interface IPersistStream;
      interface IPersistStorage;
      interface IPersistMemBlob;
      interface IPkcs7SignedData;
      interface IAmHashed;
      interface ICertificateList;
      interface ICertificateStore;

SignerInfo

      interface IUnknown;
      interface IPersistMemBlob;
      interface ISignerInfo;
      interface IAmHashed;
      interface IAmSigned;

Pkcs7 Signed data objects relationships

Figure 5 shows the relationships between some of the Pkcs7SignedData objects.

Figure 5. Pkcs7SignedData object relationships

Important Interfaces

The following interfaces are the most used and, therefore, the most important interfaces. They are presented in alphabetical order.

IAmHashed

This interface is used for hashing things that are hashable.

interface IAmHashed : IUnknown {
   HRESULT    Hash(
      [in] HCRYPTHASH  hash  // The hash key to use on the data.
      );  
   }

IAmSigned

This interface is used for signing things that are signable.

interface IAmSigned : IAmHashed {       // Note the interface inheritance.
   
     // Sign the information herein.
     //
     HRESULT  Sign(
        [in]  HCRYPTPROV   hprov,     // Crypto provider to use
        [in]  DWORD      dwKeySpec,   // Key spec of provider to use. Usually 
                                      // AT_SIGNATURE.
        [in]  ALG_ID    algidHash     // Hash algorithm to use (encryption 
                                      // alg implied  by key).
      );
     // Verify that the information herein is signed with the private key that
     // corresponds to the provided public key.
     //
     HRESULT  Verify(
        [in]  HCRYPTPROV   hprov,     // Crypto provider used for services.
        [in]  HCRYPTKEY    hkeypub    // The public key to test with.
        ); 
     // Return values:
     //
     // S_OK                Yes, it was signed with this key.
     // NTE_BAD_SIGNATURE   No, it was not signed with this key.
     //Other error code:    An error in processing prevented the determination
     //                     from being made.
     //
}

ICertificateList

This interface provides a simple way to manipulate an ordered list of certificates.

interface ICertificateList : IUnknown {
     //
     // Return the number of certificates that the list presently contains.
     //
     HRESULT  get_CertificateCount(
        [out,retval] LONG*  pccert
        );
   
     //
     // Return access to the n'th certificate.
     //
     HRESULT  get_Certificate(
        [in]          LONG                icert,   // Zero-origin index of
                                                   // certificate sought
        [in]          REFIID              iid,     // Typically IX509
        [out, iid_is(iid),retval] void**  ppv
        );
     //
     // Create a new certificate at the end of the list and return access to it.
     //
     HRESULT  create_Certificate(
        [in]         LONG                 icertBefore,  // Create before this; 
                                                        // -1 means end
        [in]         REFIID               iid,          // Typically IX509
        [out, iid_is(iid),retval] void**  ppv
        );
     //
     // Delete an existing certificate. The indices of the
     // signer infos above this shift down by one.
     //
     // If the certificate is presently open, this method fails.
     //
     HRESULT    remove_Certificate(
        [in]        LONG    icert      // Zero-origin index of certificate to
                                       // remove.
        );
     //
     // Copy the list, preserving the order.
     //
     HRESULT    CopyTo(
        [in]            ICertificateList* plistTo
        );
     }

ICertificateStore

This interface is the central interface to a body of code that can store numerous certificates. It provides basic querying functionality, as well as import/export capability.

interface ICertificateStore : IUnknown {
     // 
     // Put a new X.509 certificate into the store, given the bits of the 
     // certificate.
     //
     HRESULT    ImportCertificate(
        [in] BLOB*          pData,     // DER encoding of the certificate.
        [in] LPCOLESTR      wszID      // A unique string to tag this cert with
                                       // may be NULL.
        );
     //
     // Retrieve an X.509 certificate from the store. Return STG_E_FILENOTFOUND 
     // if the certificate cannot be located.
     //
     HRESULT    ExportCertificate(
        [in]  CERTIFICATENAMES*  pnames,   // The name(s) of the certificate to
                                           // retrieve.
        [out] LPOLESTR*          pwszId,   // The tag of this cert, if any. 
                                           // pwszId may be NULL.
      [out,retval] BLOB*         pData     // Data returned in DER encoding.
      );
     //
     // Get read-only access to a certificate with a particular name. That is, 
     // changes made to the returned certificate will NOT be reflected back into 
     // the store. Returns STG_E_FILENOTFOUND if the certificate cannot be 
     // located.
     //
     HRESULT    get_ReadOnlyCertificate(
        [in]            CERTIFICATENAMES* pnames,  // The name(s) of the 
                                                   // certificate to retrieve.
        [out]           LPOLESTR*         pwszId,  // The tag of this cert, if 
                                                   // any. pwszId may be NULL.
        [in]            REFIID            iid,     // Typically IX509.
        [out, iid_is(iid),retval] void**  ppv
        );
     //
     // Copy all the certificates in this store into the indicated destination 
     // store.
     //
     HRESULT    CopyTo(
        [in] ICertificateStore*    pStoreDest
        );
     }

ICertificateStoreAux

This is an interface that allows auxiliary information to be maintained by the store. The store associates the information with a given certificate by means of the string "tags."

interface ICertificateStoreAux : IUnknown {
//
    // Set the information associated with a given tag.
    //
    HRESULT    put_AuxInfo(
      [in]  LPCOLESTR    wszTag,
      [in]  CERTSTOREAUXINFO* pinfo
      );
    //
    // Retreieve the information associated with a given tag.
    //
    HRESULT    get_AuxInfo(
      [in]  LPCOLESTR   wszTag,
      [out] CERTSTOREAUXINFO* pinfo
      );
    //
    // Helper utility to free an information structure.
    //
    HRESULT    FreeAuxInfo(
      [in,out] CERTSTOREAUXINFO* pinfo
      );
    //
    // Return the number of tags.
    //
    HRESULT    TagCount(
      [out] LONG* pctag
      );
    //
    // Return the ith tag.
    //
HRESULT    get_Tag(
   [in]  LONG                itag,
   [out] LPOLESTR*     pwszTag
   );
}

ICertificateStoreRegInit

This is an interface on the system certificate-store implementation that provides the capability to retarget which part of the registry to use.

interface ICertificateStoreRegInit : IUnknown {
  //
  // Tell the implementation which part of the registry to use.
  // 
  HRESULT    SetRoot(
    [in] HKEY         hkey,           // eg: HKEY_LOCAL_MACHINE
    [in] LPCOLESTR    wszRoot         // Root key name to use under that key.
    );
}

IPkcs7SignedData

This interface is used for manipulating a PKCS #7 cryptographic message, which is an instance of the SignedData type defined in the PKCS #7 standard.

IPkcs7SignedData provides access to the content, the signer information, and the certificate list inside the message; for simplicity (since usage is expected to be rare) it does not provide access to the certificate-revocation lists (said access could be provided later in a new, auxiliary interface).

Instances of this interface always support ICertificateList. ICertificateStore is usually supported (in the implementation returned by CreatePkcs7SignedData, it always is).

They also support IPersistStorage, which saves the storage in a spot that doesn't interfere with hashing.

interface IPkcs7SignedData : IUnknown {
   //////////////////////////////////////////////////////////////////////
   //
   //   Generic ContentInfo Management
   //
   //////////////////////////////////////////////////////////////////////
   // Retrieve the content information and the DER encoding of the 
   // data according to its contentType. Note that while the contentType
   // is always provided, it is legal for the data itself to actually
   // be omitted; this is indcated by pinfo->data.pBlobData == NULL
   //
   HRESULT      get_ContentInfo(
      [out,retval] PKCS7_CONTENTINFO*  pinfo
      ); 
   //
   // Set the content information. Note that it is legal, as explained above,
   // for the actual content to be omitted.
   //
   HRESULT       put_ContentInfo(
      [in] PKCS7_CONTENTINFO*  pinfo
      );
   //////////////////////////////////////////////////////////////////////
   //
   // One particular kind of ContentInfo is an 'IndirectData', whose
   //  ASN.1 looks like:
   //
   //      IndirectDataContent ::= SEQUENCE {
   //           data               AttributeTypeAndOptionalValue,
   //           messageDigest      DigestInfo
   //              -- This is the message digests of the indicated data.
   //              -- (DigestInfo is defined in PKCS. It's a indication of
   //              -- the algorithm used along with the actual hash data.)
   //           } --<PDU>--
   //
   //      AttributeTypeAndOptionalValue ::= SEQUENCE {
   //           type               ATTRIBUTE.&id,
   //           value            ATTRIBUTE.&Type({...}{@type}) OPTIONAL
   //           }
   //
   //  A ContentInfo of type IndirectDataContent is used to refer to a
   //  data source that is external to the SignedData. The 'type' of 
   //  the 'data' indicates, at the least, the means by which that external
   //  data is to be hashed. 'value' is often omitted, implying that the
   //  data refers to the entity of the indicated type in which this SignedData
   //  is most immediately physically embedded. If present it usually
   //  indicates some hint (such as a file name or URL) of the data to
   //  which this SignedData refers.
   //
   //////////////////////////////////////////////////////////////////////
   HRESULT    put_IndirectDataContent(
      //
      // Set the ContentInfo of this SignedData to be an IndirectDataContent
      // that has the following information.
      //
      [in]  OSIOBJECTID*   pid,         // Id value to set in the 'data.'
      [in]  BLOB*          pBlobVale,   // The encoded contents of the 'value.'
      [in]  DIGESTINFO*    pDigest      // The digest of the referred-to data.
      );
   HRESULT    get_IndirectDataContent(
      //
      // Retrieve the IndirectDataContent that we expect to find in this
      // SignedData.
      //
      // E_FAIL is returned if all went well except that this 
      // SignedData doesn't contain the desired IndirectDataContent inside.
      //
      [in] OSIOBJECTID*   pid,       // Id value expected; error if different.
      [in] BOOL           fValueNeeded,  // Whether to bother returning the 
                                      // value .
      [out]BLOB*          pBlobValue, // The returned value, if requested.
      [out]DIGESTINFO*    pDigest     // The returned digest of the referred-
                                      // to data.
      );
   //////////////////////////////////////////////////////////////////////
   //
   // Helper functions for signing data that requires the parameters, contained
   // in the IndirectDataContent representation in the SignedData, to be a 
   // link. 
   //
   // The basic sequence of events in signing is as follows:
   //
   //  1. Create an appropriate ISignableDocument
   //  2. Call IPkcs7SignedData::HashAndSetSignableDocument, passing in the 
   //              document
   //  3. Sign the SignedData with one or more SignerInfos
   //  4. Store the signature in the signable using 
   //             IPkcs7SignedData::SaveIntoSignableDocument
   //
   // For verification, you do the reverse:
   //
   //  1. Create an appropriate signable
   //  2. Load the signature using LoadFromSignable
   //  3. Verify the basics using VerifyGeneric
   //  4. Verify the signature on the signer info using IAmSigned
   //
   //////////////////////////////////////////////////////////////////////
   HRESULT    HashAndSetSignableDocument(
      [in] ISignableDocument* pdoc,      // The source to hash.
      [in] HCRYPTPROV         hprov,     // (optional) Crypto provider to use: 
                                         // for efficiency.
      [in] ALG_ID             algidHash  // The hash algorithm to use.
      );
    
   HRESULT    SaveIntoSignableDocument(
      [in] ISignableDocument*    pSignable,
      [in] BOOL                  fClearDirty
      );
   HRESULT    LoadFromSignableDocument(
      [in] ISignableDocument*  pSignable
      );
    
   // VerifySignableDocument—The twin to HashAndSetSignableDocument.
   //
   // Verify that a) this SignedData contains an IndirectDataContent of the 
   // appropriate type of document, and b) the hash found inside said 
   // IndirectDataContent matches the current hash of the document.
   //
   // Note that we do not do signature checking; that is done, instead, on
   // SignerInfos found in this SignedData. 
   //
   // Return values:
   //    S_OK            It all matched
   //    E_FAIL          Content isn't an IndirectDataContent of the right type
   //    NTE_BAD_SIGNATURE      The hash did not match ...
   //
   HRESULT    VerifySignableDocument(
      [in] ISignableDocument*    pdoc,    // The source to verify
      [in] HCRYPTPROV            hprov,   //(optional) Crypto provider to use:
                                          //for efficiency .
      [in] ALG_ID                algidHash    // Zero means use alg indicated by 
                                              // the data.
      );
   
   //////////////////////////////////////////////////////////////////////
   //
   // Helper functionality that makes it easy to sign a flat file.
   //
   //////////////////////////////////////////////////////////////////////
   // Put/get a ContentInfo that refers indirectly to a flat file.
   //
   HRESULT    put_ContentRawFile(
      [in] PKCS7_FILEDATA* pdata
      );
   HRESULT    get_ContentRawFile(
      [out,retval] PKCS7_FILEDATA* pdata
      );
   // Even easier to use: hash the indicated file and then set the ContentInfo
   // to be IndirectDataContent that points to the indicated file. The intent
   // here is to cover the 80 percent case while letting the preceding functions
   //cover the more general cases.
   //
   HRESULT    HashAndSetRawFile(
      [in] FILEHANDLE      hFile,        // (optional) An already-open handle
                                         // to the file.
      [in] LPCOLESTR       wszFileName,  // NOT optional. the name of the file
                                         // to hash.
      [in] HCRYPTPROV      hprov,        // (optional) Crypto provider to use: 
                                         // for efficiency.
      [in] ALG_ID          algidHash     // The hash algorithm to use.
      );
   
   // VerifyRawFile-The twin to HashAndSetRawFile.
   //
   // Verify that (a) this SignedData contains an IndirectDataContent of type 
   // 'raw file', and (b) the hash found inside this IndirectDataContent matches 
   // the hash of the file indicated here as EITHER wszFileName OR hFile. 
   // Use NULL to omit wszName; 
   // INVALID_HANDLE_VALUE to omit hFile. If both are provided, hFile, is used.
   // Note that we do NOT compare the link info in the IndirectDataContent 
   // to wszFileName in any way. Note also that this does not do signature
   // checking; that instead is done on SignerInfos found in this SignedData 
   //
   // Return values:
   //      S_OK         It all matched
   //      E_FAIL       Content isn't an IndirectDataContent of type raw file
   //      NTE_BAD_SIGNATURE The hash did not match other...
   //
   HRESULT    VerifyRawFile(
      [in] FILEHANDLE     hFile,        // (optional) An already-open handle to
                                        //  the file.
      [in] LPCOLESTR      wszFileName,  // (optional) The name of the file to
                                        //  hash.
      [in] HCRYPTPROV     hprov,        // (optional) Crypto provider to use: 
                                        //  for efficiency.
      [in] ALG_ID         algidHash     //  Zero means use alg indicated by the 
                                        //  data.
      );
   //////////////////////////////////////////////////////////////////////
   // 
   //Methods for Istorages, which is analogous to that of raw files.
   //
   //////////////////////////////////////////////////////////////////////
   //
   // Note that Pkcs7SignedDatas also support IPersistStorage, by which
   // they can be loaded from/saved to an IStorage in the appropriate
   // location.

   HRESULT    put_ContentStructuredStorage(
      [in] PKCS7_FILEDATA* pdata          // Often CERT_LINK_TYPE_NONE
      );
   HRESULT    get_ContentStructuredStorage(
      [out,retval] PKCS7_FILEDATA* pdata  // Often CERT_LINK_TYPE_NONE
      );
   HRESULT    HashAndSetStorage(
      [in] IStorage*      pstg,           // The IStorage to hash.
      [in] HCRYPTPROV     hprov,          // (optional) Crypto provider to use:
                                          // for efficiency.
      [in] ALG_ID         algidHash       // The hash algorithm to use.
      );
   HRESULT    VerifyStorage(
      [in] IStorage*      pstg,           // The IStorage to hash.
      [in] HCRYPTPROV     hprov,          // (optional) Crypto provider to use:
                                          // for efficiency.
      [in]  ALG_ID        algidHash       // Zero means use alg indicated by the
                                          // data.
      );
   //////////////////////////////////////////////////////////////////////
   //
   // Methods for Image files—analogous to that of raw files
   //
   //////////////////////////////////////////////////////////////////////
   
   HRESULT    put_ContentImageFile(
      [in] PKCS7_IMAGEFILEDATA* pdata
      );
   HRESULT    ContentImageFile(
      [out] PKCS7_IMAGEFILEDATA* pdata,
      [in]  BOOL fWantFileData
      );
   
   HRESULT    HashAndSetImageFile(
      [in] DWORD         dwDigestLevel,   // CERT_PE_IMAGE_DIGEST_XXXX
                                          // flags.
      [in] FILEHANDLE    hFile,           // (optional) An already-open handle
                                          // to the file.
      [in] LPCOLESTR     wszFileName,     // NOT optional. The name of the file 
                                          // to hash.
      [in] HCRYPTPROV    hprov,           // (optional) Crypto provider to use: 
                                          // for efficiency.
      [in] ALG_ID     a  lgidHash         // The hash algorithm to use.
      );
   //
   // Verify that: 
   //  (a) this SignedData contains an IndirectDataContent of type 'image file',
   //  and (b) the hash found inside this IndirectDataContent matches the hash
   //  of the file indicated here as EITHER wszFileName OR hFile. Use NULL to 
   //  omit wszName; INVALID_HANDLE_VALUE to omit hFile. If both are provided,
   //  hFile is used.
   // 
   HRESULT    VerifyImageFile(
      [in] DWORD        dwDigestLevel,   // CERT_PE_IMAGE_DIGEST_XXXX
                                         // flags, zero==use per data indication
      [in] FILEHANDLE   hFile,           // (optional) An already-open handle to
                                         //  the file.
      [in] LPCOLESTR    wszFileName,     // (optional) The name of the file to 
                                         //  hash.
      [in] HCRYPTPROV   hprov,           // (optional) Crypto provider to use: 
                                         //  for efficiency.
      [in] ALG_ID       algidHash        //  Zero means use alg indicated by the
                                         //  data.
      );
   //////////////////////////////////////////////////////////////////////
   //
   //Methods for Java class files—analogous to that of raw files.
   //
   //////////////////////////////////////////////////////////////////////
   
   HRESULT    put_ContentJavaClassFile(
      [in] PKCS7_FILEDATA* pdata
      );
   HRESULT    get_ContentJavaClassFile(
      [out,retval] PKCS7_FILEDATA* pdata
      );
   HRESULT    HashAndSetJavaClassFile(
      [in] FILEHANDLE      hFile,         // (optional) An already-open handle 
                                          // to the file.
      [in] LPCOLESTR       wszFileName,   // NOT optional. the name of the file
                                          // to hash.
      [in] HCRYPTPROV      hprov,         // (optional) Crypto provider to use:
                                          // for efficiency.
      [in]  ALG_ID         algidHash      // The hash algorithm to use.
      );
   HRESULT    VerifyJavaClassFile(
      [in] FILEHANDLE     hFile,         // (optional) An already-open handle 
                                         //  to the file.
      [in] LPCOLESTR      wszFileName,   // (optional) The name of the file to 
                                         //  hash.
      [in] HCRYPTPROV     hprov,         // (optional) Crypto provider to use: 
                                         //  for efficiency.
      [in]  ALG_ID      algidHash        //  Zero means use alg indicated by the
                                         //  data.
      );
   HRESULT    SaveIntoJavaClassFile(
      [in] FILEHANDLE      hFile,        // (optional) An already-open handle to
                                         //  the file.
      [in] LPCOLESTR       wszFileName,  // (optional) The name of the file to 
                                         //  hash.
      [in] BOOL            fClearDirty
      );
   HRESULT    LoadFromJavaClassFile(
      [in] FILEHANDLE      hFile,         // (optional) An already-open handle
                                          //  to the file.
      [in] LPCOLESTR       wszFileName    // (optional) The name of the file
                                          //  to hash.
      );
   //////////////////////////////////////////////////////////////////////
   //////////////////////////////////////////////////////////////////////
   //
   //   SignerInfo management.
   //
   //////////////////////////////////////////////////////////////////////
   //////////////////////////////////////////////////////////////////////
   //
   // Return the number of signer infos that presently exist.
   //
   HRESULT    get_SignerInfoCount(
      [out,retval] LONG* pcinfo
      );
   
   //
   // Return access to the nth signerinfo we presently have. Callers
   // should not rely on the ordering across save / load boundaries.
   //
   HRESULT    get_SignerInfo(
      [in]              LONG iInfo,      // Zero-origin index of info sought
      [in]              REFIID iid,      // Typically ISignerInfo
      [out, iid_is(iid),retval] void** ppv
      );
   //
   // Create a new signer info at the end of the list and return access to it.
   //
   HRESULT    create_SignerInfo(
      [in]              LONG    iInfoBefore,// Create before this; -1 means end.
      [in]              REFIID  iid,        // Typically ISignerInfo
      [out, iid_is(iid),retval] void**    ppv
      );
   //
   // Delete an existing signer info. The indices of the
   // signer infos above this shift down by one.
   //
   // If any signer info is presently open, this method returns an error.
   //
   HRESULT    remove_SignerInfo(
      [in] LONG      iInfo      // Zero-origin index of info to remove.
      );
}

IPkcs10

This is an interface used for manipulating a PKCS #10 Certification Request.

Instances of this interface normally also support several other interfaces. In particular, ISelectedAttributes is supported in order to provide access to the attributes that are part of the request, but are not going into the ultimately generated certificate.

See also the method IPkcs10::get_Subject.

interface IPkcs10 : IPublicKeyContainer {
     //
     // Retrieve an object through which the subject information of the 
     // certification request may be set or inquired. The attributes set on this 
     // subject become(part of) the attributes of the issued certificate. The 
     // returned object will support (at least) ISelectedAttributes and 
     // IX500Name.
     //
     HRESULT    get_Subject(
        [in]         REFIID   iid,          // ISelectedAttributes or IX500Name
        [out, iid_is(iid),retval] void**   ppvObj
        );
}

IPublicKeyContainer

An interface that abstracts the ability to contain a public key of a public/private key pair.

interface IPublicKeyContainer : IUnknown {
     //
     // Retrieve and set the public key contained herein.
     //
     HRESULT       get_PublicKey(
        [in]       HCRYPTPROV hprov,     // Provider under which to retrieve
                                         // things.
      [out,retval] HCRYPTKEY* phkey      // Place to return the public key.
      );
     HRESULT      put_PublicKey(
        [in]      HCRYPTPROV hprov,      // Get the key from this provider...
        [in]      DWORD      dwKeySpec   //  ... and this key spec (usually 
                                         // AT_SIGNATURE).
      );
     HRESULT    get_PublicKeyBlob(
        [out,retval] BLOB* pblob         // Retrieves DER encoding of 
                                         // SubjectPublicKeyInfo.
        );
     HRESULT    put_PublicKeyBlob(
        [in]       BLOB* pblob           // DER or BER of SubjectPublicKeyInfo.
        );
     //
     // Return the necessary Cryptographic information so that you can tell what
     // kind of provider is going to be needed for this public key.
     //
     // Examples returned include:
     //
     //      CALG_RSA_SIGN
     //      CALG_DSS_SIGN
     //
     // That is, the 'signature' key spec variation is always returned;
     // if caller wishes to do 'key exchange' instead, he must map the
     // algorithm identifiers.
     //
     HRESULT    get_SignatureAlgorithm(
        [out,retval] ALG_ID* palgid
        );
    
}

IPublicKeyPair

This is a helper interface for manipulating a public-key pair generated and found in a Cryptographic Service Provider.

interface IPublicKeyPair : IUnknown {
     // Set the cryptographic provider to use. If not called, then this defaults  
     // to the default crypto provider. This is an initialization method; it 
     // must be called before any of the generation or loading methods, if it is
     // to be called at all.
     //
     HRESULT    SetProviderInfo(
        [in]  LPCWSTR       wszProviderName,
        [in]  DWORD        dwProviderType
        );
     // Generate a new key pair.
     //
     HRESULT   Generate(
        [in] HWND           hwnd,        // Parent for any user interaction 
                                         // needed.
        [in] LPCWSTR        wszKeySet,   // Optional. Key set name to use.
        [in] DWORD          dwKeySpec    // AT_SIGNATURE or AT_KEYEXCHANGE
        );
     // Save the key pair into the indicated file name.
     //
     HRESULT   Save(
        [in] HWND          hwnd,           // Parent for any user interaction 
                                           // needed.
        [in] LPCWSTR       wszKeyNickName, // Optional, defaults to wszFileName.
        [in] LPCWSTR       wszFileName     // File to save to.
      );
     // Load the key pair from the indicated file name.
     //
     HRESULT    Load
        (
        [in] LPCWSTR      wszKeySet,      // Optional. Key set name to use.
        [in] HWND         hwnd,           // Parent for any user interaction 
                                          // needed.
        [in] LPCWSTR      wszKeyNickName, // Optional, defaults to wszFileName.
        [in,out] DWORD*   pdwKeySpec,     // Optional, keyspec to load/was
                                          // loaded.
        [in] LPCWSTR      wszFileName     // File to load from.
        );
     // Save the key pair into the indicated already-open Istorage.
     //
     HRESULT   SaveStg(
        [in] HWND         hwnd,           // Parent for any user interaction
                                          // needed.
        [in] LPCWSTR      wszKeyNickName, // 
        [in] IStorage*    pstg            // IStorage to save into.
        );
     // Load the key pair from the indicated already-open Istorage.
     //
     HRESULT    LoadStg(
        [in] LPCWSTR      wszKeySet,      // Optional. Key set name to use.
        [in] HWND         hwnd,           // Parent for any user interaction
                                          // needed.
        [in] LPCWSTR      wszKeyNickName, // 
        [in,out] DWORD*   pdwKeySpec,     // Optional. keyspec to load/was
                                          //loaded.
        [in] IStorage*    pstg            // IStorage to load from.
        );
     // Return the present cryptographic information
     //
     HRESULT    GetCryptInfo(
        [in]  HWND   hwnd,                // Parent for any user interaction
                                          // needed.
        [out] HCRYPTPROV*   phprov,       // Optional.
        [out] HCRYPTKEY*   phkey,         // Optional; must be NULL if phprov is
        [out] LPWSTR*       pwszKeySet,   // Optional.
        [out] DWORD*       pdwKeySpec     // Optional.
        );
     // Destroy the key pair that is presently generated/loaded. This
     // is not done automatically.
     HRESULT    Destroy( );
}

ISelectedAttributes

This is an interface for setting and retrieving a selection of common and/or useful attributes (defined in X.501). Specifically, the attributes listed here are many of those suggested as being handy by PKCS #9, some of the ones defined in PKCS #9 itself, and a few others.

The interface can also can be used to read and write X.509 extensions instead of X.501 attributes. Typically, a given instance of this interface will either write extensions or will write attributes; an attempt to write extensions to an attribute instance will return DIGSIG_E_EXTENSIBILITY.

All maximum sizes mentioned here are per UpperBounds {joint-iso-ccitt ds(5) module(1) upperBounds(10) 2}.

interface ISelectedAttributes : IUnknown {
     //
     // Set/get an arbitrary single-valued attribute (Attribute is defined in 
     // X.501).No support is presently provided for arbitrary multi-valued 
     // attributes. When attempting to retrieve an attribute, an error of 
     // STG_E_FILENOTFOUND indicates that the requested attribute is not 
     // present.
     //
     HRESULT   put_Attribute (
        [in] OSIOBJECTID* id,       // The attribute ID to set.
        [in] BLOB*         pData    // Data in ASN.1 DER; NULL to remove 
                                    // attribute.
        );
     HRESULT   get_Attribute(
        [in]  OSIOBJECTID*      id, // The attribute ID to retrieve.
        [out,retval] BLOB*  pData   // Returned data in ASN.1 DER, NULL to not 
                                    // get data.
      );
   
     // Set/get an arbitrary X.509 v3 Extension. When attempting to retrieve an 
     // attribute, an error of STG_E_FILENOTFOUND indicates that the requested 
     // extension is not present.

     HRESULT   put_Extension
        (
        [in] OSIOBJECTID* id,       // The extension ID to set.
        [in] BOOL fCritical,        // Whether this is a critical extension or
                                    // not.
        [in] BLOB*pData             // Data in ASN.1 DER; NULL to remove 
                                    // extension.
      );
     HRESULT   get_Extension
        (
        [in]  OSIOBJECTID* id,        // The extension ID to retrieve.
        [out] BOOL*        fCritical, // Whether this is a critical extension or
                                      // not.
        [out,retval] BLOB*pData       // Returned data in ASN.1 DER, NULL to not
                                      // get data.
        );
     // Retrieve the entire list of attribute/extension object IDs that is found
     // herein.
   
     HRESULT    get_ OsiIdList(
        [out,retval] OSIOBJECTIDLIST** ppList   // Place to return newly-
                                                // allocated list of IDs.
      );
   
     // Copy this bag of attributes/extensions into another. 
     // The destination bag of attributes is NOT emptied first; we merely add to 
     // it(perhaps replacing some existing attributes with updated instances).
   
     HRESULT    CopyTo(
        [in, unique] ISelectedAttributes* pattrs   // Bag of attributes to fill.
        );
     //----------------------------
     // Helper methods for setting/getting a selected number of common
     // attributes/extensions.
   
     //
     // Set/get a generic directory string (see the ITU-T standard).
     //
     HRESULT   put_DirectoryString([in] OSIOBJECTID*pid, [in] LPCOLESTR wsz);
     HRESULT   get_DirectoryString([in] OSIOBJECTID*pid, [out,retval] LPOLESTR*
               pwsz);
     HRESULT   put_CommonName([in] LPCOLESTR wsz);
     HRESULT   get_CommonName([out,retval] LPOLESTR* pwsz);
     HRESULT   put_Surname([in] LPCOLESTR wsz);
     HRESULT   get_Surname([out,retval] LPOLESTR* pwsz);
     HRESULT   put_LocalityName([in] LPCWSTR wsz);
     HRESULT   get_LocalityName   ([out,retval] LPOLESTR* pwsz);
     HRESULT   put_CountryName   ([in] LPCOLESTR wsz);
     HRESULT   get_CountryName   ([out,retval] LPOLESTR* pwsz);
     HRESULT   put_StateOrProvinceName([in] LPCOLESTR wsz);
     HRESULT   get_StateOrProvinceName([out,retval] LPOLESTR* pwsz);
     HRESULT   put_OrganizationName   ([in] LPCOLESTR wsz);   // 64 chars max
     HRESULT   get_OrganizationName   ([out,retval] LPOLESTR* pwsz); 
                                                             // 64 ch. max
     HRESULT   put_OrganizationalUnitName([in] LPCOLESTR wsz);
     HRESULT   get_OrganizationalUnitName([out,retval] LPOLESTR* pwsz);
     //
     // From X.509 v3 DAM:
     //
     //   "This field, which can be either a certificate extension or 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."
     //
     //   These methods give access to this extension, if it is present. The 
     //   (optional) keyIdentifer field is only returned if it is the size of an 
     //   MD5Digest.
     //
     HRESULT    put_AuthorityKeyIdentifier([in] CERTIFICATENAMES* pnames);
     HRESULT    get_AuthorityKeyIdentifier([out, retval] CERTIFICATENAMES* 
     pnames);
     //
     // CertIdentifier is an attribute that is closely related to 
     // AuthorityKeyIdentifier.
     // It is intended for use in PKCS#7 SignerInfos.
     //
     // An X.509 certificate certifies (among other things) in its signed data:
     //
     //      issuer name
     //      serial number
     //      subject name
     //      subject public key
     //
     // Given just this information, an attempt can be made to locate the parent 
     // certificate. This is done by looking for a parent certificate whose 
     // subject name is the issuer name in the child certificate.
     //
     // The X.509 DAM defines infrastructure to support alternate ways of 
     // finding the parent certificate. Specifically (as used herein) it defines 
     // a certificate extension, which (in addition to the above info) 
     // indicates:
     //      parent's issuer name &  parent's serial number
     //      parent's public key
     //
     // Thus, one can now look for the parent certificate by finding a 
     // certificate whose issuer name and serial number are those of the parent 
     // as indicated in the authorityKeyIdentifier extension of the child, or 
     // whose public key is the one of the parent as indicated.
     //
     // Consider, now, PCKS#7 SignerInfos, which have a similar need to identify
     // the certificate used. Inside the SignerInfo itself one can place the:
     //
     //      parent's issuer name &  parent's serial number
     //
     // (where 'parent' is the certificate used to sign the SignerInfo).  
     // However, no support is provided for looking up by either simple parent 
     // subject name or parent public key. To provide for such uniformity, we 
     // herein define a new attribute that allows such additional information to 
     // be conveyed. This is the CertIdentifier attribute, which stores:
     //
     //      parent subject name      and / or
     //      parent public key
     //
     // (any issuerSerialNumber in the pnames paramter is ignored).
     //
     //
     HRESULT    put_CertIdentifier([in]            CERTIFICATENAMES* pnames);
     HRESULT    get_CertIdentifier([out, retval]CERTIFICATENAMES* pnames);
     //
     // Access to the 'basicConstraints' extension as defined by the X.509 DAM.
     // Support is not provided here for the (optional) 'permittedSubtrees' and 
     // 'exludedSubtrees' defined therein, other than to provide a means to 
     // indicate their presence or absence; if access to these is required, 
     // please use the generic extension/attribute mechanisms previously 
     // defined.
     //
     HRESULT    put_BasicConstraints(
        [in]    CERT_BASICCONSTRAINTS*    pConstraints,
        [in]    BOOL                      fCritical
      );
     HRESULT   get_BasicConstraints(
        [out]  CERT_BASICCONSTRAINTS*  pConstraints,      
        [in,out,unique] BOOL*       pfCritical,       // Was extension
                                                      //  critial may be NULL
        [in,out,unique] BOOL*       pfSubtreesPresent // NULL if you don't 
                                                      //  want  to know
        );
     //
     // Per the X.509 v3 DAM, the keyUsageRestriction extension can be used to 
     // restrict the set of policies under which a certified key may be used. 
     // Microsoft has defined a restricted use of this extension, known as a 
     // 'Key Purpose'. In short, a key purpose is a certificate policy element 
     // that is a yes/no predicate as to whether the key can be used for a given 
     // function. Examples of key purposes include software publisher
     // licensing, and 'windows compatibility testing' _Allowed_ 
     // purposes are indicated in the keyUsageRestriction of a certificate; when 
     // one actually signs some data, the _applied_ purpose of the signing can 
     // be indicated in the StatementType attribute (see below).
     //
     // KeyCanBeUsedForSigning answers whether the certificate can be used for 
     // creating digital signatures with the indicated purpose. If key usage 
     // restrictions are absent, then fExplicit controls whether 'yes' or 'no' 
     // is returned. If a key usage restriction is present, then a check is made 
     // that:
     //      a) The indicated purpose is a policy-element ID in at least one of 
     //         the permitted cert policies, and
     //      b) The certificate is allowed to be used for the usage 
     //         'digitalSignature' and/or 'keyCertSign'
     //
     // Note that in practice this question about whether a given key can be 
     // used for signing needs to be explicitly asked of each thing up the 
     // certification chain; this routine itself does no walking of that chain.
     //
     // Return values:
     //       S_OK      yes, it can
     //       S_FALSE   no, it cannot
     //       error     I can't tell for some reason
     //
     //
     HRESULT    get_KeyCanBeUsedForSigning(
        [in,unique] CERT_PURPOSE*   pPurpose,
        [in]      BOOL              fExplicit   // False means absence of 
                                                // restriction is ok.
        );
     //
     // The inverse of get_KeyCanBeUsedForSigning. Indicate, explicitly, that 
     // this key can be used for signing things with the given purpose.
     //
     HRESULT   put_ KeyCanBeUsedForSigning(
        [in,unique] CERT_PURPOSE*   pPurpose
        );
     HRESULT        get_MeetsMinimalFinancialCriteria(
        [out]       BOOL*      pfFinancialCriteriaAvailable,
        [out, retval] BOOL*    pfMeets
        );
     HRESULT        put_ MeetsMinimalFinancialCriteria(
        [in]        BOOL       fFinancialCriteriaAvailable,
        [in]        BOOL       fMeets
        );
     //
     // Access to the MS-defined Statement Type attribute, used, typically, in 
     // the authenticatedAttributes of SignerInfo inside a PKCS#7 SignedData.
     //
     HRESULT   put_StatementType([in]       CERT_PURPOSES* pUsages);
     HRESULT   get_StatementType([out,retval]CERT_PURPOSES**ppUsages);
     //
     // Information about an agency that issues Software Publishing Licenses.
     //
     HRESULT   put_SplAgencyInfo([in]       SPL_AGENCYINFO* pinfo);
     HRESULT   get_SplAgencyInfo([out,retval]SPL_AGENCYINFO* pinfo);
     //
     // Information about a published work of software.
     //
     HRESULT   put_SplOpusInfo([in]       SPL_OPUSINFO* pinfo);
     HRESULT   get_SplOpusInfo([out,retval]SPL_OPUSINFO* ppinfo)
     //
     // A couple of attributes from PKCS #9 that are needed in PKCS #7
     // SignerInfos.
     //
     HRESULT    put_ContentType([in ] OSIOBJECTID*     pidContentType);
     HRESULT    get_ContentType([out, retval] OSIOBJECTID** ppidContentType);
     HRESULT    put_MessageDigest([in] BLOB* pBlobDigest);
     HRESULT    get_MessageDigest([out, retval] BLOB*   pBlobDigest);
     HRESULT    put_EmailAddress([in] LPCOLESTR wsz);
     HRESULT    get_EmailAddress   ([out, retval] LPOLESTR*   pwsz);
     HRESULT    put_SigningTime([in,  unique] FILETIME* pftUtc);   // NULL uses
                                                                   // 'now'
     HRESULT    get_SigningTime([out, retval] FILETIME* pftUtc);
     HRESULT    put_UnstructuredName([in] LPCWSTR wsz);      // PKCS#9
     HRESULT    get_UnstructuredName([out,retval] LPWSTR* pwsz);   // PKCS#9
     HRESULT    put_GivenName([in] LPCOLESTR wsz);
     HRESULT    get_GivenName([out,retval] LPOLESTR* pwsz);
     HRESULT    put_Initials([in] LPCOLESTR wsz);
     HRESULT    get_Initials([out,retval] LPOLESTR* pwsz);
     HRESULT    put_Title([in] LPCOLESTR wsz);               // 64 chars max
     HRESULT    get_Title([out,retval] LPOLESTR* pwsz);         // 64 chars max
     //----------------------------
     HRESULT    put_StreetAddress([in] LPCWSTR wsz);
     HRESULT    get_StreetAddress([out,retval] LPWSTR* pwsz);
   
     HRESULT    put_PostalCode([in] LPCWSTR wsz);            // 40 chars max
     HRESULT    get_PostalCode([out,retval] LPWSTR* pwsz);      // 40 chars max
     HRESULT    put_PostOfficeBox([in] LPCWSTR wsz);         // 40 chars max
     HRESULT    get_PostOfficeBox([out,retval] LPWSTR* pwsz);    // 40 chars max
     HRESULT    put_PhysicalDeliveryOfficeName([in] LPCWSTR wsz);  // 128 ch max
     HRESULT    get_PhysicalDeliveryOfficeName([out,retval] LPWSTR* pwsz); 
                                                                  // 128  max
     HRESULT    UnstructuredAddress([in] LPCWSTR wsz);
     HRESULT    UnstructuredAddress([out,retval] LPWSTR* pwsz);
   
   //----------------------------
     HRESULT    put_TelephoneNumber([in] LPCWSTR wsz);   // 32 chars max,
                                          // printable chars only
     HRESULT    get_TelephoneNumber([out,retval] LPWSTR* pwsz); // 32 chars max,
                                          //   printable chars only 
     HRESULT    put_FaxTelephoneNumber([in] LPCWSTR wsz);      // 32 chars max,
                                          //   printable chars only
     HRESULT    get_FaxTelephoneNumber([out,retval] LPWSTR* pwsz);   // 32 chars
                                                                     // max, 
                                          //   printable chars only 
     //----------------------------
     HRESULT    put_ChallengePassword([in] LPCWSTR wsz);
     HRESULT    get_ChallengePassword([out,retval] LPWSTR* pwsz);
}

ISignableDocument

An interface used on an object that participates in the generic signing process in IPkcs7SignedData.

Notice that this interface derives from IAmHashed.

interface ISignableDocument : IAmHashed {
     //
     // Return the information to go into the IndirectDataContent
     // that indicates the flavor of indirect data in question.
     //
     HRESULT      get_DataIdentifier(
        [out] OSIOBJECTID** ppid
        );
     //
     // Get a reference to the location of this data.
     //
     HRESULT      get_DataLocation(
        [out]  CERT_LINK* plink    // CERT_LINK_TYPE_NONE is legal
        );
    
     //
     // Load the signature block from this data.
     //
     HRESULT      LoadSignature(
        [out,retval]   BLOB* pBlobSignature
        );
     //
     // Insert the signature block into this data.
     //
     HRESULT    SaveSignature(
        [in]   BLOB* pBlobSignature
        );
     };

ISignerInfo

This interface is used to manipulate a PKCS #7 SignerInfo structure. Typically, instances are created and manipulated using IPkcs7SignedData::SignerInfo.

Instances of this interface also support IAmSigned, by which the actual signing is carried out.

interface ISignerInfo : IUnknown {
     //
     // Return access to the authenticated attributes.
     //
     HRESULT    get_AuthenticatedAttributes(
        [in]            REFIID    iid,      // Typically ISelectedAttributes
        [out, iid_is(iid),retval] void** ppv
        );
   
     //
     // Return access to the unauthenticated attributes.
     //
     HRESULT    get_UnauthenticatedAttributes(
        [in]            REFIID iid,          // Typically ISelectedAttributes
        [out, iid_is(iid),retval] void** ppv
        );
     //
     // If we have ANY authenticated attributes, then update/create 
     // those that MUST be there per PKCS#7. This is done automatically
     // if the SignerInfo is signed; this method allows it to be done
     // manually so that the correct hash may be extracted if desired.
     // Note, however, that signing is the ONLY thing that will automatically
     // update; in particular, saving will not.
     //
     HRESULT    UpdateRequiredAuthenticatedAttributes(
        [in]  HCRYPTPROV     hprov,      // Crypto provider to use for hash
        [in]  ALG_ID         algidHash   // Hash algorithm to use (encryption
                                         //    alg implied by  key)
        );
     // 
     // Access to the information about the certificate used
     // in signing this signer info.
     //
     HRESULT      put_CertificateUsed(
        [in] CERTIFICATENAMES*    pnames
        );
     HRESULT      get_CertificateUsed(
        [out,retval] CERTIFICATENAMES* pnames
        );
     }

IX509

IX509 is the central interface used for manipulating an X.509 certificate. Instances of IX509 almost always support ISelectedAttributes (in extensions mode) as a means by which extensions to the certificate can be read or written. Its definition is as follows:

interface IX509 : IPublicKeyContainer {
     //
     // Set/get the serial number in the certificate.
     //
     HRESULT   get_SerialNumber(
        [out,retval] CERTSERIAL*    pserial
        );
     HRESULT    put_SerialNumber(
        [in] CERTSERIAL*       pserial
        );
     //
     // Get access to the issuer name of this certificate.
     //
     HRESULT                   get_Issuer(
        [in]                       REFIID   iid,      // Usually IX500Name or 
                                                      // IPersistMemBlob
        [out, iid_is(iid),retval] void**    ppv
        );
     //
     // This certificate, if it belongs to a CA, may be used to certify other 
     // certificates. In such a child certificate, the name of *this*  
     // certificate needs to be stored as a means of indicating the parent 
     // certificate in the chain. This method returns the names by which this 
     // certificate should be so known when used as such a parent certificate in 
     // a chain.
     //
     HRESULT get_CertificateNames(
        [in]       HCRYPTPROV         hprov,     // (Optional; provide 
                                                 // for performance.)
      [out,retval] CERTIFICATENAMES*  pnames
      );
     //
     // Get access to the subject name of this certificate.
     //
     HRESULT    get_Subject(
        [in]                REFIID       iid,   // Usually IX500Name or 
                                                // IPersistMemBlob.
        [out, iid_is(iid),retval] void** ppv
        );
     //
     // Set/get the validity period of the certificate.
     //
     HRESULT    get_Validity(
        [out] FILETIME*   pftUtcNotBefore,
        [out] FILETIME*   pftUtcNotAfter
        );
     HRESULT    put_Validity(
        [in]  FILETIME*   pftUtcNotBefore,
        [in]  FILETIME*   pftUtcNotAfter
        );
     //
     // A handy helper that sets the start of the validity
     // as 'now' and the end as the indicated number of 
     // months in the future.
     //
     HRESULT    put_ValidityDuration(
        [in] WORD      nMonths
        );
     //
     // A handy helper that answers whether the certificate
     // is valid at the indicated time: S_OK==YES, S_FALSE==NO, or
     // error==can't tell.
     //
     HRESULT   IsInValidityPeriod(
        [in, unique] FILETIME*    pftUtc   // If NULL, the current date & time
                                           // is used.
        );
     // 
     // A handy helper that returns ALL the names that are available for the
     // parent certificate.
     //
     HRESULT      get_CertificateUsed(
        [out,retval] CERTIFICATENAMES*    pnames
        );
  }

IX500Name

This interface is for manipulating an X500Name instance as defined in the X.501 specification.

interface IX500Name : IUnknown {
   ////////////////////////////////////////////////////////////////////////////
   //
   // Simple, common access.
   //
   ////////////////////////////////////////////////////////////////////////////
   // Convert the name to a string form in the standard syntax and return it.
   //
   // Example: "C=US; OU=Microsoft; 1.2.3.4=Some Custom String Attribute; 
   // CN=Joe Howard;"
   //
   HRESULT    get_String(
      [out,retval] LPOLESTR*    posz
      );
   //
   // Set our full name from the indicated string. This cannot be called
   // while any RDN's are outstanding per the above.
   //
   HRESULT    put_String(
      [in] LPCOLESTR    osz
      );
   ////////////////////////////////////////////////////////////////////////////
   //
   // Full power, less-common access.
   //
   ////////////////////////////////////////////////////////////////////////
   //
   // Return the number of relative distinguished names in the name.
   //
   HRESULT    get_RelativeDistinguishedNameCount(
      [out,retval] LONG*    pcrdn      // Place to return count.
      );
   //
   // Return an accessor to the irdn'th (zero-origin) relative distinguished 
   // name.
   //
   HRESULT    get_RelativeDistinguishedName(
      [in]  LONG             irdn,      // Zero-origin index of relative name.
      [in]  REFIID           iid,       // iid sought, usually
                                        // ISelectedAttributes.
      [out, iid_is(iid),retval] void**   ppv
      );
   //
   // Create a new RelativeDistinguishedName at the end of the list
   // and return access to it.
   //
   HRESULT    create_RelativeDistinguishedName(
      [in]  LONG             irdnBefore,   // Create before this; -1 means end.
      [in]  REFIID           iid,          // iid sought, usually 
                                           // ISelectedAttributes.
      [out, iid_is(iid),retval] void**    ppv
      );
   //
   // Remove a particular RDN. This cannot be called while any RDNs are 
   // outstanding.
   //
   HRESULT    remove_RelativeDistinguishedName(
      [in] LONG irdn               // zero-origin index of name to remove.
      );
   //
   // Copy this name into another. We, of course, replace 
   // the contents of the destination name entirely.
   //
   HRESULT    CopyTo(
      [in,unique] IX500Name* pname   // Name to copy into.
      );
}