在WinHTTP中使用SSL

来源:互联网 发布:程序员和黑客的区别 编辑:程序博客网 时间:2024/04/30 05:23

在WinHTTP中使用SSL

Microsoft Windows HTTP Services (WinHTTP) supports Secure Sockets Layer (SSL) transactions including client certificates. This topic explains concepts involved in an SSL transaction and how they are handled using WinHTTP.

WinHTTP支持包含客户证书的SSL交互。本主题将讲解SSL交互概念及WinHTTP如何使用它。

Secure Sockets Layer(安全套接字层)

SSL is an established standard for ensuring secure HTTP transactions. SSL provides a mechanism to perform up to 128-bit encryption on all transactions between the client and server. It enables the client to verify that the server belongs to a trusted entity through the use of server certificates. It also enables the server to confirm the identity of the client with client certificates.

SSL是个已建立的标准安全HTTP交互过程。SSL可以为客户端与服务器之间所有的通信提供128bit加密。它可以让用户通过验证服务器的证书来验证其可信性。同理服务器也可以验证客户的证书是否合法。

Each of these issues—encryption, server identity, and client identity—are negotiated in the SSL handshake that occurs when a client first requests a resource from a Secure Hypertext Transfer Protocol (HTTPS) server. Essentially, the client and server each present a list of required and preferred settings. If a common set of requirements can be agreed upon and met, an SSL connection is established.

上述每个问题-加密,服务器验证和客户端验证-将会在客户端向服务器发出HTTPS请求时通过握手过程完成。实质上,客户端和服务器端每方都保存有一个列表和一些可选的设置。如果达到通用设置要求,那么SSL连接就可以被建立。

WinHTTP provides a high level interface for using SSL. While the details of the SSL handshake and transaction are handled internally, WinHTTP enables you to retrieve encryption levels, specify the security protocol, and interact with server and client certificates. The following sections provide details on creating WinHTTP based applications that elect an SSL protocol version, examine server certificates, and select client certificates to send to HTTPS servers.

WinHTTP为使用SSL提供了高层接口。这样SSL握手交换在内部得以处理。WinHTTP使你获取加密等级,设置加密协议,操作服务器和客户端证书。下面章节讲述了基于WinHTTP如何创建SSL协议,测试服务器证书,选择客户端证书发送到HTTPS服务器。

Server Certificates

服务器证书

Server certificates are sent from the server to the client so that the client can obtain a public key for the server and ensure that the server has been verified by a certification authority. Certificates can contain different types of data. For example, an X.509 certificate includes the format of the certificate, the serial number of the certificate, the algorithm used to sign the certificate, the name of the certification authority (CA) that issued the certificate, the name and public key of the entity that requests the certificate, and the CA's signature.

从服务器发送给客户的证书称为服务器证书,这样客户就可获取一个服务器的公钥,以此确保服务器可以通过证书验证。证书可以包含不同信息。例如一个X.509证书包含证书类型、证书序列号、证书签名算法,证书颁发机构名称,证书的名字和公钥需要证书和证书签名。

When using the WinHTTP  application programming interface (API), you can retrieve a server certificate by callingWinHttpQueryOption and specifying the WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT flag. The server certificate is returned in aWINHTTP_CERTIFICATE_INFO structure. If you prefer to retrieve the certificate context, specify theWINHTTP_OPTION_SERVER_CERT_CONTEXT flag instead.

当使用WinHTTP API时,你可以通过调用WinHttpQueryOption(使用WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT标识)获取服务器证书。服务器证书以一个WINHTTP_CERTIFICATE_INFO结构体返回。如果你想获得证书内容,使用WINHTTP_OPTION_SERVER_CERT_CONTEXT标识。

If a server certificate contains errors, details about the error can be obtained in the status callback function. TheWINHTTP_CALLBACK_STATUS_SECURE_FAILURE notification indicates an error with a server certificate. ThelpvStatusInformation parameter contains one or more detailed error flags. SeeWINHTTP_STATUS_CALLBACK for more information.

如果服务器证书包含错误,可以通过状态回调函数获取。WINHTTP_CALLBACK_STATUS_SECURE_FAILURE通知表明有服务器证书错误发生。lpvStatusInformation参数包含一个或多个错误细节。查看WINHTTP_STATUS_CALLBACK以获取更详细信息。

Client Certificates

客户证书

During the SSL handshake, the server might require authentication. The client is authenticated by supplying a valid client certificate to the server. WinHTTP enables you to select and send a certificate from a localcertificate store. The following sections describe the process that provides client certificates when using either the WinHTTP API or theWinHttpRequest object.

在SSL握手过程中,服务器也会验证客户。客户的认证使用过提供一个合法的客户证书来完成。WinHTTP使你能够从本地证书缓存中选取和发送一个证书。下面章节将讨论这个过程,它通过使用WinHTTPAPI或WinHttpRequest对象完成。

WinHTTP API

Both WinHttpSendRequest and WinHttpReceiveResponse can fail to indicate that a request was unsuccessful because the HTTPS server requires authentication. In these cases, callGetLastError to returns ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. Upon receiving this error, use the appropriateCryptoAPI functions to find an appropriate certificate. Indicate that this certificate should be sent with the next request by callingWinHttpSetOption with the WINHTTP_OPTION_CLIENT_CERT_CONTEXT flag.

WinHttpSendRequestWinHttpReceiveResponse都可以通过错误来表明因为服务器要求验证请求失败。这种情况下,要配合调用GetLastError函数,如果返回ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED。依靠收到这样的错误,使用合适的CryptoAPI函数来确定恰当的认证方法。下面就要使用WinHttpSetOption(使用WINHTTP_OPTION_CLIENT_CERT_CONTEXT

The following code example shows how to open a certificate store and locate a certificate based on subject name after the ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED error has been returned.

下面例程展示了在收到ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED后,如何打开客户本地certificate store然后发送。

C++
  if( !WinHttpReceiveResponse( hRequest, NULL ) )  {    if( GetLastError( ) == ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )    {      //MY is the store the certificate is in.      hMyStore = CertOpenSystemStore( 0, TEXT("MY") );      if( hMyStore )      {        pCertContext = CertFindCertificateInStore( hMyStore,             X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,             0,             CERT_FIND_SUBJECT_STR,             (LPVOID) szCertName, //Subject string in the certificate.             NULL );        if( pCertContext )        {          WinHttpSetOption( hRequest,                             WINHTTP_OPTION_CLIENT_CERT_CONTEXT,                            (LPVOID) pCertContext,                             sizeof(CERT_CONTEXT) );          CertFreeCertificateContext( pCertContext );        }        CertCloseStore( hMyStore, 0 );        // NOTE: Application should now resend the request.      }    }  }

Before resending a request that contains a client certificate, you can determine if the supported level of encryption is acceptable for your application. CallWinHttpQueryOption and specify the WINHTTP_OPTION_SECURITY_FLAGS flag to determine the level of encryption that is used.

在重发送带客户认证的请求前,你可以探测下你的程序是否支持要求的加密级别。调用WinHttpQueryOption并设置WINHTTP_OPTION_SECURITY_FLAGS来查询加密级别。

Issuer List Retrieval for SSL Client Authentication

SSL客户认证的问题列表

When the WinHttp client application sends a request to a secure HTTP server that requires SSL client authentication, WinHttp returns anERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED if the application has not supplied a client certificate. For computers running on Windows Server 2008 and Windows Vista, WinHttp enables the application to retrieve the certificate issuer list supplied by the server in the authentication challenge. The Issuer List specifies a list of Certificate Authorities (CAs) that are authorized by the server to issue client certificates. The application filters the issuer list to obtain the required certificate.

当WinHTTP客户向HTTPs服务器发送请求,会返回一个ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED错误,如果程序不支持客户证书。比如运行Windows2008和Vista的主机,WinHTTP让程序可以获取挑战后服务器提供的认证问题列表。这个列表中指出了服务器认可的证书颁发机构。程序通过这个列表来筛查出需要的证书。

The WinHttp client application retrieves the issuer list when WinHttpSendRequest, or WinHttpReceiveResponse returns ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED. When this error is returned, the application callsWinHttpQueryOption with the WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST option. ThelpBuffer parameter must be large enough to contain a pointer to the SecPkgContext_IssuerListInfoEx structure. The following code example shows how to retrieve the issuer list.

当WinHttpSendRequest, 或WinHttpReceiveResponse返回ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED错误时,WinHttp客户程序获取问题列表,当这个错误发生时,要使用WinHttpQueryOption配合WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST选项。lpBuffer参数必须有足够空间容纳指向SecPkgContext_IssuerListInfoEx的指针。下面代码展示了如何获取这个列表。

C++
#include <windows.h>#include <winhttp.h>#include <schannel.h>//...void GetIssuerList(HINTERNET hRequest){  SecPkgContext_IssuerListInfoEx* pIssuerList = NULL;  DWORD dwBufferSize = sizeof(SecPkgContext_IssuerListInfoEx*);  if (WinHttpQueryOption(hRequest,           WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST,           &pIssuerList,           &dwBufferSize) == TRUE)  {    // Use the pIssuerList for cert store filtering.    GlobalFree(pIssuerList); // Free the issuer list when done.  }}

The information in the SecPkgContext_IssuerListInfoEx structure, cIssuers and aIssuers, can be used to search for the certificate as shown in the code example below. For more information, seeCertFindChainInStore.

SecPkgContext_IssuerListInfoEx结构体中的信息-cIssuersaIssuers可被用来查找证书,如下例。

详情请看CertFindChainInStore

C++
PCERT_CONTEXT pClientCert = NULL;PCCERT_CHAIN_CONTEXT pClientCertChain = NULL;CERT_CHAIN_FIND_BY_ISSUER_PARA SrchCriteria;::ZeroMemory(&SrchCriteria, sizeof(CERT_CHAIN_FIND_BY_ISSUER_PARA));SrchCriteria.cbSize = sizeof(CERT_CHAIN_FIND_BY_ISSUER_PARA);SrchCriteria.cIssuer = pIssuerList->cIssuers;SrchCriteria.rgIssuer = pIssuerList->aIssuers;pClientCertChain = CertFindChainInStore(            hClientCertStore,            X509_ASN_ENCODING,            CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG |            // Do not perform wire download when building chains.            CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG,            // Do not search pCacheEntry->_ClientCertStore             // for issuer certs.            CERT_CHAIN_FIND_BY_ISSUER,            &SrchCriteria,            NULL);if (pClientCertChain){    pClientCert = (PCERT_CONTEXT) pClientCertChain->rgpChain[0]->rgpElement[0]->pCertContext;    CertDuplicateCertificateContext(pClientCert);    CertFreeCertificateChain(pClientCertChain);    pClientCertChain = NULL;}

Optional Client SSL Certificates

可选客户证书

Starting in Windows Server 2008 and Windows Vista, the WinHttp API supports optional client certificates. When the server requests a client certificate,WinHttpSendRequest, or WinHttpRecieveResponse returns an ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED error. If the server requests the certificate, but does not require it, the application can specify this option to indicate that it does not have a certificate. The server can choose another authentication scheme or allow anonymous access to the server. The application specifies theWINHTTP_NO_CLIENT_CERT_CONTEXT macro in the lpBuffer parameter ofWinHttpSetOption as shown in the following code example.

从Windows Server 2008 和Vista以后,WinHTTP API支持可选客户证书。当服务器要求客户证书,WinHttpSendRequest, 或WinHttpRecieveResponse返回一个ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED错误,如果服务器要求想要证书,但并不非得要,客户程序就可以设定这个选项来表明它没有证书,服务器可以通过选择另外一种方式来验证客户或让客户匿名访问。下例展示了WinHttpSetOption通过设置lpBuffer参数中的WINHTTP_NO_CLIENT_CERT_CONTEXT宏。

BOOL fRet = WinHttpSetOption ( hRequest,                               WINHTTP_OPTION_CLIENT_CERT_CONTEXT,                               WINHTTP_NO_CLIENT_CERT_CONTEXT,                               0);

If the WINHTTP_NO_CLIENT_CERT_CONTEXT is set, and the server still requires a client certificate, it may send a 403 HTTP status code. For more information, see theWINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST option.

如果WINHTTP_NO_CLIENT_CERT_CONTEXT被设置,服务器仍然要求验证客户证书,它就会发送一个403状态码。详情参见WINHTTP_OPTION_CLIENT_CERT_ISSUER_LIST选项。

WinHttpRequest 对象


Use the SetClientCertificate method of the WinHttpRequest object to select client certificates to send to the server with a request. Select a certificate by specifying a certificate selection string with theSetClientCertificate method. The certificate selection string consists of the certificate location,certificate store, and subject name delimited by backslashes. The following table lists components for this selection string.

使用WinHttpRequest对象的SetClientCertificate方法来选择客户证书然后发送到服务器完成请求。通过使用SetClientCertificate指定证书选择字符串信息来选择一个证书,这个证书选择字符串包含证书位置,证书存储区和对象名称(通过反斜杠)分隔。下表列出了选择信息组件。

组件描述可能 的值Location

Determines the registry key under which the certificates are stored.

判定注册表键值中存储的证书

可能的值是 "LOCAL_MACHINE" 表明 certificate store

HKEY_LOCAL_MACHINE下

和"CURRENT_USER" to indicate that the certificate store is under the non-impersonated

HKEY_CURRENT_USER.

大小写敏感.Certificate store标明包含相关证书certificate store名称。一般certificate stores 是"MY", "Root", 和"TrustedPeople". 大小写敏感。Subject name在 certificate store中的标识符。第一个包含指定字符的证书将被选中。对象名称可以是任意字符串.为空时标识  certificate store 中第一个证书将被应用.大小写不敏感。

 

The certificate store name and location are optional components. However, if you specify acertificate store, you must also specify the location of that certificate store. The default location is CURRENT_USER and the defaultcertificate store is "MY".

certificate store的名称和位置是可选组件,然而,如果你指定了一个证书存储区,你也必须指定certificate store位置。默认的位置是CURRENT_USER,默认的证书存储区是“MY”

The following code example shows how to specify that a certificate with the subject "My Middle-Tier Certificate" should be chosen from the "Personal"certificate store in the registry under HKEY_LOCAL_MACHINE.

下面代码展示了如何指定一个证书,证书主题是"My Middle-Tier Certificate",选择的存储区是"Personal",注册表位置在HKEY_LOCAL_MACHINE下。

HttpReq.SetClientCertificate("LOCAL_MACHINE\Personal\My Middle-Tier Certificate")

Note  In some languages the backslash is an escape character. Remember to modify the certificate selection string to account for this. For example, in Microsoft JScript, use two adjacent backslashes instead of one.
注意 在某些语言下反斜杠是无效字符。记得要针对性改变。比如在微软JScript使用双反斜杠而不是一个。

If you do not specify a certificate and an HTTPS server requires a client certificate, WinHTTP selects the first certificate in the defaultcertificate store. If no certificates exist, an error is raised. If the certificate is not accepted, the server returns a 403 status code to indicate that the request cannot be fulfilled. You can then choose a more appropriate certificate withSetClientCertificate and resend the request.

如果你没有指定证书并且HTTPS服务器要求证书,WinHTTP会从默认存储区中选择第一个证书。如果证书不存在,会抛出一个错误,如果证书没被接受,服务器返回403错误,然后你就要使用SetClientCertificate重新选择证书,重发请求

 

0 0
原创粉丝点击