Vérifier qu’un certificat prend en charge une méthode de signature

Cette rubrique explique comment vérifier qu’un certificat prend en charge une méthode de signature spécifique.

CryptXmlEnumAlgorithmInfo dans l’API Microsoft Crypto énumère les propriétés d’un certificat et est utilisé dans cet exemple de code pour énumérer les méthodes de signature prises en charge par le certificat. Pour utiliser CryptXmlEnumAlgorithmInfo pour énumérer les méthodes de signature que le certificat prend en charge, l’appelant doit fournir une méthode de rappel et une structure de données dans l’appel à CryptXmlEnumAlgorithmInfo, ce qui lui permet de transmettre des données à la méthode de rappel.

La structure de données utilisée dans l’exemple de code suivant contient les champs suivants :

Champ Description
userSignatureAlgorithmToCheck Un champ LPWSTR qui pointe vers la chaîne qui contient l’URI de l’algorithme de signature à vérifier.
certificateAlgorithmInfo Un pointeur vers une structure CRYPT_OID_INFO qui contient des informations sur un algorithme de signature pris en charge par le certificat.
userSignatureAlgorithmSupported Une valeur booléenne qui indique si l’algorithme de signature est pris en charge par le certificat.

 

struct SignatureMethodData
{
    LPCWSTR             userSignatureAlgorithmToCheck; 
    PCCRYPT_OID_INFO    certificateAlgorithmInfo; 
    BOOL                userSignatureAlgorithmSupported; 
};

La méthode d’API Crypto qui vérifie le certificat utilise une méthode de rappel pour retourner des données à l’appelant. CryptXmlEnumAlgorithmInfo énumère les méthodes de signature que le certificat prend en charge et appelle la méthode de rappel pour chaque méthode de signature jusqu’à ce que la méthode de rappel retourne FALSE ou jusqu’à ce que toutes les méthodes de signature du certificat aient été énumérées.

La méthode de rappel dans l’exemple de code suivant recherche une méthode de signature passée par CryptXmlEnumAlgorithmInfo qui correspond à la méthode de signature fournie par la méthode appelante. Lorsqu’une correspondance est trouvée, la méthode de rappel vérifie si la méthode de signature est également prise en charge par le système. Si les méthodes de signature correspondent et sont prises en charge par le système, la méthode de signature est marquée comme prise en charge par le système et la méthode de rappel retourne FALSE.

BOOL WINAPI 
EnumSignatureMethodCallback (
    __in const CRYPT_XML_ALGORITHM_INFO *certMethodInfo,
    __inout_opt void *userArg
)
{
    // MAX_ALG_ID_LEN is used to set the maximum length of the 
    // algorithm URI in the string comparison. The URI is not 
    // likely to be longer than 128 characters so a fixed-size
    // buffer is used in this example.
    // To make this function more robust, you might consider
    // setting this value dynamically.
    static const size_t MAX_ALG_ID_LEN = 128;
    SignatureMethodData *certificateAlgorithmData = NULL;

    if (NULL != userArg) {
        // Assign user data to local data structure
        certificateAlgorithmData = (SignatureMethodData*)userArg;
    } else {
        // Unable to continue this enumeration 
        //   without data from calling method.
        return FALSE;
    }
    
    // For each algorithm in the enumeration, check to see if the URI 
    //  of the algorithm supported by the certificate matches the URI 
    //  of the algorithm being tested.
    int cmpResult = 0;
    cmpResult = wcsncmp( 
        certMethodInfo->wszAlgorithmURI, 
        certificateAlgorithmData->userSignatureAlgorithmToCheck, 
        MAX_ALG_ID_LEN );
    if ( 0 == cmpResult )
    {
        // This is a match...
        // Check to see if the algorithm supported by the 
        //  certificate matches any of the supported algorithms 
        //  on the system.
        cmpResult = wcsncmp(
            certMethodInfo->wszCNGExtraAlgid, 
            certificateAlgorithmData->certificateAlgorithmInfo->pwszCNGAlgid, 
            MAX_ALG_ID_LEN );
        if ( 0 == cmpResult )
        {
            // This is also a match so set the field in the data structure
            //   provided by the calling method.
            certificateAlgorithmData->userSignatureAlgorithmSupported = TRUE;
            // A match was found so there is no point in continuing 
            //  the enumeration.
            return FALSE;
        }
    }
    // The enumeration stops when the callback method returns FALSE. 
    //   If here, then return TRUE because a matching algorithm has
    //   not been found.
    return TRUE;
}

L’exemple de code suivant encapsule la fonctionnalité de validation dans une seule méthode. Cette méthode retourne une valeur booléenne qui indique si le certificat prend en charge la méthode de signature et si la méthode de signature est prise en charge par le système.

BOOL 
SupportsSignatureAlgorithm (
    __in LPCWSTR signingMethodToCheck,
    __in PCCERT_CONTEXT certificateToCheck
)
{
    HRESULT     hr = S_OK;

    // Initialize the structure that contains the   
    //  information about the signature algorithm to check
    SignatureMethodData        certificateAlgorithmData;

    certificateAlgorithmData.userSignatureAlgorithmSupported = 
        FALSE;
    certificateAlgorithmData.userSignatureAlgorithmToCheck = 
        signingMethodToCheck;

    // Call the crypt API to get information about the algorithms
    //   that are supported by the certificate and initialize 
    //   certificateAlgorithmData
    certificateAlgorithmData.certificateAlgorithmInfo = CryptFindOIDInfo (
        CRYPT_OID_INFO_OID_KEY,
        certificateToCheck->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId,
        CRYPT_PUBKEY_ALG_OID_GROUP_ID | CRYPT_OID_PREFER_CNG_ALGID_FLAG);

    if (certificateAlgorithmData.certificateAlgorithmInfo != NULL)
    {
        // Enumerate the algorithms that are supported by the 
        //   certificate, and use our callback method to determine if
        //   the user supplied signature algorithm is supported by 
        //     the certificate.
        //
        // Note that CRYPT_XML_GROUP_ID_SIGN is used to enumerate
        //  the signature methods
        hr = CryptXmlEnumAlgorithmInfo(
            CRYPT_XML_GROUP_ID_SIGN,  // NOTE: CRYPT_XML_GROUP_ID_SIGN
            CRYPT_XML_FLAG_DISABLE_EXTENSIONS,
            (void*)&certificateAlgorithmData,
            EnumSignatureMethodCallback);
        // when the enumeration has returned successfully, 
        //  certificateAlgorithmData.userSignatureAlgorithmSupported
        //  will be TRUE if the signing method is supported by
        //  the certificate
    }
    return certificateAlgorithmData.userSignatureAlgorithmSupported;
}

Étapes suivantes

Charger un certificat à partir d’un fichier

Vérifier que le système prend en charge une méthode Digest

Incorporer des chaînes de certificats dans un document

Utilisé dans cet exemple

CryptFindOIDInfo

CRYPT_OID_INFO

CryptXmlEnumAlgorithmInfo

Pour plus d'informations

API Chiffrement

Fonctions de chiffrement

Erreurs de l’API Signature numérique XPS

Erreurs de document XPS

XML Paper Specification