Beta Release
September 10, 1996
(Preliminary)
Microsoft Corporation
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
Certificates
Certificate Store
Certificate Requests
Signature Blocks
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.
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.
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:
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.
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.
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.
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:
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.
Quite a number of broadly used standards exist in the area of public key cryptography and digital signatures. Among these are:
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.
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:
DirectoryString ::= CHOICE {
teletexString TeletexString,
printableString PrintableString,
universalString UniversalString
}
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.
id-at-commonName OBJECT IDENTIFIER ::= {id-at 3}
id-at-surname OBJECT IDENTIFIER ::= {id-at 4}
id-at-serialNumber OBJECT IDENTIFIER ::= {id-at 5}
id-at-countryName OBJECT IDENTIFIER ::= {id-at 6}
id-at-localityName OBJECT IDENTIFIER ::= {id-at 7}
id-at-collectiveLocalityName OBJECT IDENTIFIER ::= {id-at 7 1}
id-at-stateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8}
id-at-collectiveStateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8 1}
id-at-streetAddress OBJECT IDENTIFIER ::= {id-at 9}
id-at-collectiveStreetAddress OBJECT IDENTIFIER ::= {id-at 9 1}
id-at-organizationName OBJECT IDENTIFIER ::= {id-at 10}
id-at-collectiveOrganizationName OBJECT IDENTIFIER ::= {id-at 10 1}
id-at-organizationalUnitName OBJECT IDENTIFIER ::= {id-at 11}
id-at-collectiveOrganizationalUnitName OBJECT IDENTIFIER ::= {id-at 11 1}
id-at-title OBJECT IDENTIFIER ::= {id-at 12}
id-at-description OBJECT IDENTIFIER ::= {id-at 13}
id-at-searchGuide OBJECT IDENTIFIER ::= {id-at 14}
id-at-businessCategory OBJECT IDENTIFIER ::= {id-at 15}
id-at-postalAddress OBJECT IDENTIFIER ::= {id-at 16}
id-at-collectivePostalAddress OBJECT IDENTIFIER ::= {id-at 16 1}
id-at-postalCode OBJECT IDENTIFIER ::= {id-at 17}
id-at-collectivePostalCode OBJECT IDENTIFIER ::= {id-at 17 1}
id-at-postOfficeBox OBJECT IDENTIFIER ::= {id-at 18}
id-at-collectivePostOfficeBox OBJECT IDENTIFIER ::= {id-at 18 1}
id-at-physicalDeliveryOfficeName OBJECT IDENTIFIER ::= {id-at 19}
Some of these even have standard abbreviations, such as CN for "id-at-commonName," and OU for "id-at-organizationalUnitName."
C=US; OU=Microsoft; CN=Paul Borm;
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 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:
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.
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:
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:
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.
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.
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
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
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
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
The following interfaces are the most used and, therefore, the most important interfaces. They are presented in alphabetical order.
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.
);
}
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.
//
}
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
);
}
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
);
}
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
);
}
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.
);
}
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.
);
}
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
);
}
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
);
}
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( );
}
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);
}
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
);
};
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 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
);
}
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.
);
}