delphi microsoft-edge cryptoapi mutual-authentication

Delphi autenticación mutua



microsoft-edge cryptoapi (2)

Utilizo la biblioteca WinINet para conectarme a un sitio web.

Al usar Internet Explorer (Win10), funciona y me muestra el mensaje para seleccionar el certificado que se va a usar.

Este es el código delphi que llamo:

FUNCTION TRAD.lastOrganization(): Integer; VAR js:TlkJSONobject; ws: TlkJSONstring; url, resp: String; count,statusCodeLen, bodyCodeLen: Cardinal; header,tmp: String; buffer, body: String; statusCode: ARRAY [0 .. 1024] OF Char; bodyCode: ARRAY [0 .. 1024] OF Char; UrlHandle: HINTERNET; BEGIN buffer := ''00000000000000000000''; url := contextUrl + ''/rest/organization/count''; UrlHandle := InternetOpenUrl(NetHandle, PChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0); IF NOT ASSIGNED(UrlHandle) THEN SHOWMESSAGE(''Unable to read the amount of Organization using the URL '' + url + '': '' + SysErrorMessage(GetLastError)); statusCodeLen := Length(statusCode); bodyCodeLen := Length(bodyCode); count := 0; IF HttpQueryInfo(UrlHandle, HTTP_QUERY_STATUS_CODE, @statusCode[0], statusCodeLen, count) THEN BEGIN buffer := statusCode; IF buffer <> ''200'' THEN BEGIN ShowMessage(''While read amount of Organization I got a status code '' + buffer + '' but 200 was expected.''); EXIT; END; END; count := 0; body := ''''; REPEAT FillChar(bodyCode, bodyCodeLen, 0); IF NOT InternetReadFile(UrlHandle, @bodyCode[0], bodyCodeLen, count) THEN BEGIN ShowMessage(''Problem on reading from response stream while read the amount of Organization using the URL '' + url + ''.''); EXIT; END; IF count > 0 THEN BEGIN tmp := bodyCode; body := body + LeftStr(tmp, count); END; UNTIL count = 0; InternetCloseHandle(UrlHandle); Result := strtoint(body); END;

Si llamo al método, recibo este mensaje:

Buuut, utilizando el navegador de bordes, tengo que especificar un certificado, y funciona muy bien.

Pregunta

¿Cómo especificar el certificado?

Editar (nuevas informaciones):

Si cambio el código a

FUNCTION TRAD.lastOrganization(): Integer; VAR js:TlkJSONobject; ws: TlkJSONstring; url, resp: String; count,statusCodeLen, bodyCodeLen: Cardinal; header,tmp: String; buffer, body: String; statusCode: ARRAY [0 .. 1024] OF Char; bodyCode: ARRAY [0 .. 1024] OF Char; UrlHandle: HINTERNET; BEGIN buffer := ''00000000000000000000''; url := contextUrl + ''/rest/organization/count''; UrlHandle := InternetOpenUrl(NetHandle, PChar(url), nil, 0, INTERNET_FLAG_RELOAD, 0); IF NOT ASSIGNED(UrlHandle) THEN raiseLastOSError();

Muestra:


Considere el uso de InternetErrorDlg

Ejemplo de código:

function WebSiteConnect(const UserAgent: string; const Server: string; const Resource: string;): string; var hInet: HINTERNET; hConn: HINTERNET; hReq: HINTERNET; dwLastError:DWORD; nilptr:Pointer; dwRetVal:DWORD; bLoop: boolean; port:Integer; begin hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); if hInet = nil then exit; hConn := InternetConnect(hInet, PChar(Server), INTERNET_DEFAULT_HTTPS_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0); if hConn = nil then begin InternetCloseHandle(hInet); exit; end; hReq := HttpOpenRequest(hConn, ''GET'', PChar(Resource), ''HTTP/1.0'', nil, nil, INTERNET_FLAG_SECURE, 0); if hReq = nil then Begin InternetCloseHandle(hConn); InternetCloseHandle(hInet); exit; end; bLoop := true; while bLoop do begin if HttpSendRequest(hReq, nil, 0, nil, 0) then dwLastError := ERROR_SUCCESS else dwLastError:= GetLastError(); if dwLastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then begin dwRetVal:= InternetErrorDlg(application.handle, hReq, dwLastError, FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_GENERATE_DATA or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, nilptr ); if dwRetVal = ERROR_INTERNET_FORCE_RETRY then continue else // CANCEL button begin InternetCloseHandle(hReq); InternetCloseHandle(hConn); InternetCloseHandle(hInet); exit; end; end else bLoop := false; end; Result:= ... end;


Usando WinHTTP (puedes hacer lo mismo con WinInetHTTP) puedes configurar el certificado de esta manera a través de ActiveX:

// Instantiate a WinHttpRequest object. var HttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); // Open an HTTP connection. HttpReq.Open("GET", "https://www.fabrikam.com/", false); // Select a client certificate. HttpReq.SetClientCertificate( "LOCAL_MACHINE//Personal//My Middle-Tier Certificate"); // Send the HTTP Request. HttpReq.Send();

Así que fácil con ActiveX, pero no es realmente lo que quieres (te di el ejemplo como ilustración). Por lo tanto, con la API de Windows, WinHTTP le permite seleccionar y enviar un certificado desde un almacén de certificados local. El siguiente ejemplo de código muestra cómo abrir un almacén de certificados y localizar un certificado basado en el nombre del sujeto después de que se haya devuelto el error ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED.

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