確認憑證支援簽章方法

本主題描述如何確認憑證支援特定的簽章方法。

Microsoft Crypto API 中的 CryptXmlEnumAlgorithmInfo 會列舉憑證的屬性,並在此程式碼範例中用來列舉憑證支援的簽章方法。 若要使用 CryptXmlEnumAlgorithmInfo 列舉憑證支援的簽章方法,呼叫端必須在對 CryptXmlEnumAlgorithmInfo 的呼叫 中提供回呼方法和資料結構,讓它將資料傳遞至回呼方法。

下一個程式碼範例中使用的資料結構具有下欄欄位:

欄位 描述
userSignatureAlgorithmToCheck 指向 包含要檢查之簽章演算法 URI 的字串的 LPWSTR 欄位。
certificateAlgorithmInfo CRYPT_OID_INFO 結構的指標 ,其中包含憑證所支援之簽章演算法的相關資訊。
userSignatureAlgorithmSupported 布林 值,指出憑證是否支援簽章演算法。

 

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

檢查憑證的 Crypto API 方法會使用回呼方法將資料傳回給呼叫端。 CryptXmlEnumAlgorithmInfo 會列舉憑證支援的簽章方法,並呼叫每個簽章方法的回呼方法,直到回呼方法傳回 FALSE ,或直到列舉憑證中的所有簽章方法為止。

下一個程式碼範例中的回檔方法會搜尋 CryptXmlEnumAlgorithmInfo 傳入 的簽章方法,該方法符合呼叫方法所提供的簽章方法。 找到相符專案時,回呼方法會檢查系統是否也支援簽章方法。 如果簽章方法符合且系統支援,則簽章方法會標示為系統支援,而回呼方法會傳 回 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;
}

下列程式碼範例會將驗證功能包裝成單一方法。 這個方法會傳 回 Boolean 值,指出憑證是否支援簽章方法,以及系統是否支援簽章方法。

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;
}

後續步驟

從檔案載入憑證

確認系統支援 Digest 方法

在檔中內嵌憑證鏈結

在此範例中使用

CryptFindOIDInfo

CRYPT_OID_INFO

CryptXmlEnumAlgorithmInfo

詳細資訊

密碼編譯 API

密碼編譯函式

XPS 數位簽章 API 錯誤

XPS 檔錯誤

XML 紙張規格