Jump to content

Recommended Posts

Posted (edited)

Hello Trancexx,

Thanks for your contribution,I've learned more from your UDF.

I need SSL certificate info from remote server,"https://www.autoitscript.com" for example.Codes below can get some certificate info as  ExpiryTime, Subject etc..

post-59594-0-54216400-1425356985_thumb.p

Actually I need "Subject Alternative Name" info like "DNS Name=www.autoitscript.com DNS Name=autoitscript.com" from the certificate,It seems this info is contained in the "extention" part of certificate.Could any one point me how should I do? Thanks!

#include <WinHttp.au3>

Global Const $tagINTERNET_CERTIFICATE_INFO = "dword ExpiryTime[2]; dword StartTime[2]; ptr SubjectInfo; " & _
    "ptr IssuerInfo; ptr ProtocolName; ptr SignatureAlgName; ptr EncryptionAlgName; dword KeySize"
$hOpen = _WinHttpOpen()
_WinHttpSetOption($hOpen, $WINHTTP_OPTION_SECURITY_FLAGS, 0x00003300) ; $SECURITY_FLAG_IGNORE_ALL
$hConnect = _WinHttpConnect($hOpen, "www.autoitscript.com", 443)
$hRequest = _WinHttpSimpleSendSSLRequest($hConnect, "GET", "/")

    ; I don't know why I failed to get info via _WinHttpQueryOption
;~ Global $tBuffer = _WinHttpQueryOption($hRequest, $WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT)
;~ Global $tINTERNET_CERTIFICATE_INFO = DllStructCreate($tagINTERNET_CERTIFICATE_INFO, DllStructGetPtr($tBuffer))
;~ Global $tInfo = DllStructCreate("wchar [128]", DllStructGetData($tINTERNET_CERTIFICATE_INFO, "SubjectInfo"))
;~ Global $Info = DllStructGetData($tInfo, 1)
;~ ConsoleWrite('SSLCertificate Info: ' & @CRLF & $Info & @CRLF & @CRLF)

$tBufferLength = DllStructCreate("dword")
DllStructSetData($tBufferLength, 1, 2048)
$tBuffer = DllStructCreate("byte[2048]")
$avResult = DllCall($hWINHTTPDLL__WINHTTP, "bool", "WinHttpQueryOption", _
        "handle", $hRequest, _
        "dword", $WINHTTP_OPTION_SECURITY_CERTIFICATE_STRUCT, _
        "struct*", DllStructGetPtr($tBuffer), _
        "dword*", DllStructGetPtr($tBufferLength))
If Not @error And $avResult[0] Then
    $tINTERNET_CERTIFICATE_INFO = DllStructCreate($tagINTERNET_CERTIFICATE_INFO, DllStructGetPtr($tBuffer))

    ; Get Subject
    $tInfo = DllStructCreate("wchar [128]", DllStructGetData($tINTERNET_CERTIFICATE_INFO, "SubjectInfo"))
    $Info = DllStructGetData($tInfo, 1)
    ConsoleWrite('SSLCertificate Info: ' & @CRLF & $Info & @CRLF & @CRLF)

    ;Get ExpiryTime
    $tInfo = DllStructCreate("int64", DllStructGetPtr($tINTERNET_CERTIFICATE_INFO, "ExpiryTime"))
    $Info = DllStructGetData($tInfo, 1)
    ConsoleWrite('SSLCertificate Info: ' & @CRLF & $Info & @CRLF & @CRLF)

    ; How to get SSL certificate extention info? I need "Subject Alternative Name" like "DNS Name=www.autoitscript.com DNS Name=autoitscript.com"
EndIf
$tBufferLength = 0
$tBuffer = 0
$tINTERNET_CERTIFICATE_INFO = 0
$tInfo = 0

_WinHttpCloseHandle($hRequest)
_WinHttpCloseHandle($hConnect)
_WinHttpCloseHandle($hOpen)
Edited by jackchen
  • 1 month later...
Posted (edited)

To get extensions info you should query for $WINHTTP_OPTION_SERVER_CERT_CONTEXT and then use Certificate functions to read data.
Something like this (no error checking here):
 

#include "WinHttp.au3"

$hOpen = _WinHttpOpen()
$hConnect = _WinHttpConnect($hOpen, "https://www.facebook.com")
$hRequest = _WinHttpSimpleSendSSLRequest($hConnect)

; Query for CERT_CONTEXT pointer
$tBuffer = DllStructCreate("ptr")
DllCall($hWINHTTPDLL__WINHTTP, "bool", "WinHttpQueryOption", _
  "handle", $hRequest, _
  "dword", $WINHTTP_OPTION_SERVER_CERT_CONTEXT, _
  "struct*", $tBuffer, _
  "dword*", DllStructGetSize($tBuffer))

ConsoleWrite("> CERT_CONTEXT pointer: " & DllStructGetData($tBuffer, 1) & @CRLF)

; Close handles
_WinHttpCloseHandle($hRequest)
_WinHttpCloseHandle($hConnect)
_WinHttpCloseHandle($hOpen)


$pContext = DllStructGetData($tBuffer, 1)

Const $CERT_NAME_DNS_TYPE = 6
Const $CERT_NAME_SEARCH_ALL_NAMES_FLAG = 0x2

; Read size of the needed buffer
$aCall = DllCall("Crypt32.dll", "dword", "CertGetNameString", _
        "ptr", $pContext, _
        "dword", $CERT_NAME_DNS_TYPE, _
        "dword", $CERT_NAME_SEARCH_ALL_NAMES_FLAG, _
        "dword*", 0, _
        "struct*", 0, _
        "dword", 0)
$iSize = $aCall[0]

; Create buffer
$tStruct = DllStructCreate("byte[" & $iSize & "]")

; Read DNS names
$aCall = DllCall("Crypt32.dll", "dword", "CertGetNameString", _
        "ptr", $pContext, _
        "dword", $CERT_NAME_DNS_TYPE, _
        "dword", $CERT_NAME_SEARCH_ALL_NAMES_FLAG, _
        "dword*", 0, _
        "struct*", $tStruct, _
        "dword", $iSize)

; Free CERT_CONTEXT
DllCall("Crypt32.dll", "dword", "CertFreeCertificateContext", "ptr", $pContext)

; Split on NULL character and convert to array
$aArr = StringSplit(BinaryToString(DllStructGetData($tStruct, 1)), Chr(0), 2)

ConsoleWrite("Subject Alternative Name - DNS Name=" & @CRLF)
For $i = 0 To UBound($aArr) - 1
    ConsoleWrite(@TAB & $aArr[$i] & @CRLF)
Next

 

...Sorry for not replying earlier.

Edited by trancexx

♡♡♡

.

eMyvnE

  • 1 month later...
Posted

Hi Manadar,

I'd like to catch the HTTP Status Responses when pushing messages. Since the WinHttp UDF always been my nemesis I have trouble to figure out how to do that.

If found some hints in the help file but I can't figure out how to add this to the SimpleFormFill: "Last (superfluous) $sAdditionalData argument can be used to pass authorization credentials in form "[CRED:username,password]", magic string to ignore cerificate errors in form "[IGNORE_CERT_ERRORS]" and/or HTTP request header data to add. "

I'm still unsure if this even does what I want it to do. I just want to be able to receive the 200 OK or possible error responses (500 etc).

I know it has been a long time since you posted in this topic. Maybe someone else can help me out.

 

Hey Raizeno,

try this:

#include "WinHttp.au3"

$sAddress = "https://api.pushover.net/1/messages.json"

$sApiToken = "av26ac2nAXLyPKg2QMy4zf9YcUjz2G" ; <-yours here
$sUserKey = "uMQf396GvMgrsDroaryKEvVyWkgfkw" ; <-yours here
$sMessage = "hello world"

; Construct the form
Const $sForm = '<form action="' & $sAddress & '" method="post">' & _
'<input name="token" value="' & $sApiToken & '"/>' & _
'<input name="user" value="' & $sUserKey & '"/>' & _
'<input name="message" value="' & $sMessage & '"/>' & _
'</form>'

; Open session
$hOpen = _WinHttpOpen()
; To collect connection handle (because the form is inlined)
$hConnect = $sForm

; Fill the form
$sRead = _WinHttpSimpleFormFill($hConnect, $hOpen)

; Close handles
_WinHttpCloseHandle($hConnect)
_WinHttpCloseHandle($hOpen)

; Tada mtfk!
MsgBox(4096, "Simon says", $sRead)

Posted (edited)

Hi, First thanks for this wonderful UDF!

I am sending simple Get request to a server's API that response with json data.

I noticed that the json data is truncated and partially data is received by the client

Can you please let me know what should be done to capture all data?

 

I have this code to send the get method

Func BIPRequest($URL, $HTTPMethod, $HTTPSources = "", $JSON = '', $SaveHeaders = False, $SaveResponse = False, $ReadCookie = True, $SaveCookie = False, $Folder = @ScriptDir,$name="")
    Local $hOpen = _WinHttpOpen()
    Local $hConnect = _WinHttpConnect($hOpen, $URL)

    Local $hRequest = _WinHttpOpenRequest($hConnect, $HTTPMethod, $HTTPSources, Default, Default, Default, $WINHTTP_FLAG_SECURE)

    ; set options
    Local $CurrentOption = _WinHttpQueryOption($hRequest, $WINHTTP_OPTION_SECURITY_FLAGS)
    Local $Options = BitOR($CurrentOption, _
            $SECURITY_FLAG_IGNORE_UNKNOWN_CA, _
            $SECURITY_FLAG_IGNORE_CERT_CN_INVALID, _
            $SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
    _WinHttpSetOption($hRequest, $WINHTTP_OPTION_SECURITY_FLAGS, $Options)

    ; Send request
    If $ReadCookie = True Then
        _WinHttpAddRequestHeaders($hRequest, "Cookie: " & String(ReadCookie($Folder)))
    EndIf
    _WinHttpSendRequest($hRequest, "Content-type: application/json", $JSON)

    ; Wait for the response
    _WinHttpReceiveResponse($hRequest)

    ; ...get full header
    Local $sHeader = _WinHttpQueryHeaders($hRequest)

    If $SaveCookie = True Then
        SaveCookie($sHeader,$Folder)
    EndIf
    ; ...get full data
    Local $sData = _WinHttpReadData($hRequest)

    ; Clean/Close handles
    _WinHttpCloseHandle($hRequest)
    _WinHttpCloseHandle($hConnect)
    _WinHttpCloseHandle($hOpen)

    ; Display retrieved header
    MsgBox(0, "Header", $sHeader)

    ; Display retrieved data
    MsgBox(0, "Data", $sData)

    If $SaveResponse = true Then
        SaveTestResponse($name, $sData ,$name)
    EndIf

EndFunc   ;==>BIPRequest

 

Edited by lsakizada

Be Green Now or Never (BGNN)!

Posted (edited)

Please ignore my last post. I found the solution and it is very simple :'(

Needs to set the $iNumberOfBytesToRead default value of 8192 to $X bytes...

Func _WinHttpReadData($hRequest, $iMode = Default, $iNumberOfBytesToRead = Default, $pBuffer = Default)

 

 

Edited by lsakizada

Be Green Now or Never (BGNN)!

Posted

^^ Actually changing $iNumberOfBytesToRead isn't correct solution, because often you don't know how many bytes are there to read (chunked transfer encoding).
More correct is to read in loop until all the data is read. See the help file entry for _WinHttpReadData.

Also, your function can be reduced to a great degree by using set of _WinHttpSimple... functions.

♡♡♡

.

eMyvnE

Posted

You may want to try something like this:

Local $sResponse = ''

If _WinHttpQueryHeaders($hRequest, $WINHTTP_QUERY_STATUS_CODE) == $HTTP_STATUS_OK Then
    If _WinHttpQueryDataAvailable($hRequest) Then
        While True
            $sResponse &= _WinHttpReadData($hRequest)
            If @extended Then
                ; --- Nothing to do
            Else
                ExitLoop
            EndIf
        WEnd

        If $sResponse Then
            ; --- Nothing to do
        Else
            Debug('Server.class | _WinHttpReadData() failed.', @ScriptLineNumber)
            _WinHttpCloseHandle($hRequest)
            Return $this.Result['InternetError']
        EndIf
    Else
        Debug('Server.class | _WinHttpQueryDataAvailable() failed.', @ScriptLineNumber)
        _WinHttpCloseHandle($hRequest)
        Return $this.Result['InternetError']
    EndIf
Else
    Debug('Server.class | _WinHttpQueryHeaders() failed.', @ScriptLineNumber)
    _WinHttpCloseHandle($hRequest)
    Return $this.Result['InternetError']
EndIf

_WinHttpCloseHandle($hRequest)

ConsoleWrite($sResponse)

 

Posted

Hi,

I'm trying to get and save the results of a php webpage. The URL is:

"https://username:password@www.example.com/admin/report.php?startDate=2015-05-26"

where the date at the end will be configured by my script. In a browser this would result in a plain text page like this:

"Debbie","SMITH (Debbie)","Request Access: ","2015-05-31 17:29:47","2015-05-31 17:29:49","2015-05-31 19:10:57","301.8333333333333",""
"Eric,"JONES (Eric)","End Access: ","2015-05-31 18:16:00","2015-05-31 18:16:02","2015-05-31 18:44:12","46.86666666666667",""   and so on.

I'm trying to figure out how to do this with WinHttp. Note that going to "https://www.example.com" gets immediately redirected to a different page. Here's what I've tried:

#include <WinHttp.au3>
#include <WinHttpConstants.au3>

$URL = "https://www.example.com/admin"
$username = "username"
$password = "password"
$Data = "nccs.php?startDate=2015-05-31"

Global $hw_open = _WinHttpOpen("WinHTTP Example4")
If @error Then 
    MsgBox(48, "Error", "Error initializing the usage of WinHTTP functions.")
    Exit
EndIf

Global $hw_connect = _WinHttpConnect($hw_open, $URL)
If @error Then 
    MsgBox(48, "Error", "Error specifying the initial target server of an HTTP request.")
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

Global $h_openRequest = _WinHttpOpenRequest($hw_connect, "GET", $Data)
If @error Then 
    MsgBox(48, "Error", "Error creating an HTTP request handle.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpSetCredentials($h_openRequest, $WINHTTP_AUTH_TARGET_SERVER, $WINHTTP_AUTH_SCHEME_BASIC, $username, $password)
If @error Then 
    MsgBox(48, "Error", "Unable to set Credentials.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpSendRequest($h_openRequest)
If @error Then 
    MsgBox(48, "Error", "Error sending the specified request.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpReceiveResponse($h_openRequest)
If @error Then 
    MsgBox(48, "Error", "Error ReceiveResponse.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

If _WinHttpQueryDataAvailable($h_openRequest) Then
    Global $header = _WinHttpQueryHeaders($h_openRequest)
    If @error Then 
        MsgBox(48, "Error", "Error QueryHeaders.")
        _WinHttpCloseHandle($hw_connect)
        _WinHttpCloseHandle($hw_open)
        Exit
    Endif

    Global $data
    While 1
        $data &= X_WinHttpReadData($h_openRequest)
        If Not @extended Then ExitLoop      
    WEnd

Else 
    MsgBox(48, "Error", "Error QueryDataAvailable.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
EndIf

_WinHttpCloseHandle($h_openRequest)
_WinHttpCloseHandle($hw_connect)
_WinHttpCloseHandle($hw_open)

FileWrite ("header.txt", $header)
FileWrite ("data.txt",  $data)

Func X_WinHttpReadData($hRequest, $iNumberOfBytesToRead = 8192)

    Local $lpBuffer = DllStructCreate("char[" & $iNumberOfBytesToRead & "]")

    Local $a_iCall = DllCall("Winhttp.dll", "int", "WinHttpReadData", _
            "hwnd", $hRequest, _
            "ptr", DllStructGetPtr($lpBuffer), _
            "ulong", $iNumberOfBytesToRead, _
            "dword*", 0)
    
    If @error Or Not $a_iCall[0] Then
        SetError(1, 0, "")
    EndIf
    
    Return SetError(0, $a_iCall[4], DllStructGetData($lpBuffer, 1))
    
EndFunc

The Header.txt contains:

HTTP/1.1 400 Bad Request
Date: Tue, 02 Jun 2015 20:24:06 GMT
Server: Apache/2.2.29 (Amazon)
Vary: Accept-Encoding
Content-Length: 449
Connection: close
Content-Type: text/html; charset=iso-8859-1

And the Data.txt contains:

nccs.php?startDate=2015-05-31<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
 Instead use the HTTPS scheme to access this URL, please.<br />
</p>
<hr>
<address>Apache/2.2.29 (Amazon) Server at example.com Port 443</address>
</body></html>

Any suggestions and help would be greatly appreciated!

-Marc

Posted

I'm new to WinHTTP (have been using inetread/inetget for a while, and found that I couldn't figure out how to get around the 30 second timeout with them), and have been looking/testing/face-palming/trying again for the past day trying to figure out why I'm unable to get the following code to function as I expect.  Basically, everything works when communicating with SSL sites that have valid certificates, and plain HTTP sites that don't use SSL.  On internal sites with self-signed certificates (haven't been able to get the certs yet), the _WinHttpSimpleSendSSLRequest returns error code 2.  I found reference somewhere that WinHTTP may require setting options, then retrying the request with self-signed certs, but adding the below logic yields a bunch more error code 2's from the _WinHttpSimpleSendSSLRequest and the directives that follow it in the code snippet below.  I started off using the simple send request (as commented below), but then moved to the SSL variant as I was dealing with https sites.

Is there a procedure I'm missing for sending GET-type queries using WinHTTP to a site with self-signed certificates?

 

#include "WinHTTP.au3"
#include "WinHTTPconstants.au3"

    $sQueryDomain = "https://Self-Signed.internal.pvt"
    $sQueryData = "tools/query?call=test&intVar=4&output=plain"

        $hHTTPopen = _WinHttpOpen()
            If @error Then
                _TrayLog("Error Opening HTTP Session", 1)
            Else

                _TrayLog("Successfully Opened HTTP Session", 1)
                _WinHttpSetTimeouts($hHTTPopen, 5000, Default, 99999000, 99999000)
                If @error Then
                    _TrayLog("Error Setting HTTP Timeouts", 1)
                Else
                    _TrayLog("Successfully Set HTTP Timeouts", 1)
                EndIf

                $hHTTPconnect = _WinHttpConnect($hHTTPopen, $sQueryDomain)
                If @error Then
                    _TrayLog("Error Connecting to HTTP Domain", 1)
                Else

                    _TrayLog("Successfully Connected to HTTP Domain", 1)
;~                  $hHTTPrequest = _WinHttpSimpleSendRequest($hHTTPconnect, Default, $sQueryData)
                    $hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData)
                    If @error Then
                        _TrayLog("Error Issuing HTTP Request: " & @error, 1)
                        _TrayLog("---Trying Again After Setting Options---", 1)

                        $CurrentOption = _WinHttpQueryOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS)
                        If @error Then
                            _TrayLog("Error Querying HTTP Option", 1)
                        Else

                            _TrayLog("Successfully Queried HTTP Option", 1)
                            $Options = BitOR($CurrentOption, $SECURITY_FLAG_IGNORE_UNKNOWN_CA, $SECURITY_FLAG_IGNORE_CERT_CN_INVALID, $SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
                            _WinHttpSetOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS, $Options)
                            If @error Then
                                _TrayLog("Error Setting HTTP Option: " & @error, 1)
                            Else
                                _TrayLog("Successfully Set HTTP Option", 1)
                            EndIf

                        EndIf

                        $hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData)
                        If @error Then
                            _TrayLog("Error Issuing HTTP Request a Second Time: " & @error, 1)
                        Else
                            _TrayLog("Successfully Issued HTTP Request After Option Change", 1)
                        EndIf

                    Else

                        _TrayLog("Successfully Issued HTTP Request", 1)
                        $CurrentOption = _WinHttpQueryOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS)
                        If @error Then
                            _TrayLog("Error Querying HTTP Option", 1)
                        Else

                            _TrayLog("Successfully Queried HTTP Option", 1)
                            $Options = BitOR($CurrentOption, $SECURITY_FLAG_IGNORE_UNKNOWN_CA, $SECURITY_FLAG_IGNORE_CERT_CN_INVALID, $SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
                            _WinHttpSetOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS, $Options)
                            If @error Then
                                _TrayLog("Error Setting HTTP Option: " & @error, 1)
                            Else
                                _TrayLog("Successfully Set HTTP Option", 1)
                            EndIf

                        EndIf

                    EndIf

                    $bQueryData = _WinHttpSimpleReadData($hHTTPrequest, 2)
                    If @error Then
                        _TrayLog("Error Reading HTTP Data: " & @error, 1)
                    Else
                        _TrayLog("Successfully Read HTTP Data", 1)
                    EndIf

                    _WinHttpCloseHandle($hHTTPrequest)
                    _WinHttpCloseHandle($hHTTPconnect)

                EndIf

                _WinHttpCloseHandle($hHTTPopen)

            EndIf

    Func _TrayLog($_s_Msg,$_b_CreateBubble=False)
        TraySetToolTip($_s_Msg)
        If $_b_CreateBubble Then
            TrayTip(@ScriptName,$_s_Msg,2)
        EndIf
    EndFunc

 

Many thanks for any assistance you can provide,

bPi

Posted

I'm new to WinHTTP (have been using inetread/inetget for a while, and found that I couldn't figure out how to get around the 30 second timeout with them), and have been looking/testing/face-palming/trying again for the past day trying to figure out why I'm unable to get the following code to function as I expect.  Basically, everything works when communicating with SSL sites that have valid certificates, and plain HTTP sites that don't use SSL.  On internal sites with self-signed certificates (haven't been able to get the certs yet), the _WinHttpSimpleSendSSLRequest returns error code 2.  I found reference somewhere that WinHTTP may require setting options, then retrying the request with self-signed certs, but adding the below logic yields a bunch more error code 2's from the _WinHttpSimpleSendSSLRequest and the directives that follow it in the code snippet below.  I started off using the simple send request (as commented below), but then moved to the SSL variant as I was dealing with https sites.

Is there a procedure I'm missing for sending GET-type queries using WinHTTP to a site with self-signed certificates?

 

#include "WinHTTP.au3"
#include "WinHTTPconstants.au3"

    $sQueryDomain = "https://Self-Signed.internal.pvt"
    $sQueryData = "tools/query?call=test&intVar=4&output=plain"

        $hHTTPopen = _WinHttpOpen()
            If @error Then
                _TrayLog("Error Opening HTTP Session", 1)
            Else

                _TrayLog("Successfully Opened HTTP Session", 1)
                _WinHttpSetTimeouts($hHTTPopen, 5000, Default, 99999000, 99999000)
                If @error Then
                    _TrayLog("Error Setting HTTP Timeouts", 1)
                Else
                    _TrayLog("Successfully Set HTTP Timeouts", 1)
                EndIf

                $hHTTPconnect = _WinHttpConnect($hHTTPopen, $sQueryDomain)
                If @error Then
                    _TrayLog("Error Connecting to HTTP Domain", 1)
                Else

                    _TrayLog("Successfully Connected to HTTP Domain", 1)
;~                  $hHTTPrequest = _WinHttpSimpleSendRequest($hHTTPconnect, Default, $sQueryData)
                    $hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData)
                    If @error Then
                        _TrayLog("Error Issuing HTTP Request: " & @error, 1)
                        _TrayLog("---Trying Again After Setting Options---", 1)

                        $CurrentOption = _WinHttpQueryOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS)
                        If @error Then
                            _TrayLog("Error Querying HTTP Option", 1)
                        Else

                            _TrayLog("Successfully Queried HTTP Option", 1)
                            $Options = BitOR($CurrentOption, $SECURITY_FLAG_IGNORE_UNKNOWN_CA, $SECURITY_FLAG_IGNORE_CERT_CN_INVALID, $SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
                            _WinHttpSetOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS, $Options)
                            If @error Then
                                _TrayLog("Error Setting HTTP Option: " & @error, 1)
                            Else
                                _TrayLog("Successfully Set HTTP Option", 1)
                            EndIf

                        EndIf

                        $hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData)
                        If @error Then
                            _TrayLog("Error Issuing HTTP Request a Second Time: " & @error, 1)
                        Else
                            _TrayLog("Successfully Issued HTTP Request After Option Change", 1)
                        EndIf

                    Else

                        _TrayLog("Successfully Issued HTTP Request", 1)
                        $CurrentOption = _WinHttpQueryOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS)
                        If @error Then
                            _TrayLog("Error Querying HTTP Option", 1)
                        Else

                            _TrayLog("Successfully Queried HTTP Option", 1)
                            $Options = BitOR($CurrentOption, $SECURITY_FLAG_IGNORE_UNKNOWN_CA, $SECURITY_FLAG_IGNORE_CERT_CN_INVALID, $SECURITY_FLAG_IGNORE_CERT_DATE_INVALID)
                            _WinHttpSetOption($hHTTPrequest, $WINHTTP_OPTION_SECURITY_FLAGS, $Options)
                            If @error Then
                                _TrayLog("Error Setting HTTP Option: " & @error, 1)
                            Else
                                _TrayLog("Successfully Set HTTP Option", 1)
                            EndIf

                        EndIf

                    EndIf

                    $bQueryData = _WinHttpSimpleReadData($hHTTPrequest, 2)
                    If @error Then
                        _TrayLog("Error Reading HTTP Data: " & @error, 1)
                    Else
                        _TrayLog("Successfully Read HTTP Data", 1)
                    EndIf

                    _WinHttpCloseHandle($hHTTPrequest)
                    _WinHttpCloseHandle($hHTTPconnect)

                EndIf

                _WinHttpCloseHandle($hHTTPopen)

            EndIf

    Func _TrayLog($_s_Msg,$_b_CreateBubble=False)
        TraySetToolTip($_s_Msg)
        If $_b_CreateBubble Then
            TrayTip(@ScriptName,$_s_Msg,2)
        EndIf
    EndFunc

 

Many thanks for any assistance you can provide,

bPi

​_WinHttpSimpleSendSSLRequest will close request handle and return 0 in case of error (including cert errors). That's why you can't do anything with it.

 I don't know what version of WinHttp.au3 you use, but some time ago I added new parameter for _WinHttpSimpleSendSSLRequest to be able to ignore cert errors. This parameter is used internally when needed, so it's not documented. Anyway, if you want you can use it like this:

$hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData, Default, Default, Default, True)

... to make request ignoring cert errors.

Btw, why do you query security flags? Who cares what they are. If you want to ignore cert errors just set flags you want.

♡♡♡

.

eMyvnE

Posted (edited)

Hi,

I'm trying to get and save the results of a php webpage. The URL is:

"https://username:password@www.example.com/admin/report.php?startDate=2015-05-26"

where the date at the end will be configured by my script. In a browser this would result in a plain text page like this:

"Debbie","SMITH (Debbie)","Request Access: ","2015-05-31 17:29:47","2015-05-31 17:29:49","2015-05-31 19:10:57","301.8333333333333",""
"Eric,"JONES (Eric)","End Access: ","2015-05-31 18:16:00","2015-05-31 18:16:02","2015-05-31 18:44:12","46.86666666666667",""   and so on.

I'm trying to figure out how to do this with WinHttp. Note that going to "https://www.example.com" gets immediately redirected to a different page. Here's what I've tried:

#include <WinHttp.au3>
#include <WinHttpConstants.au3>

$URL = "https://www.example.com/admin"
$username = "username"
$password = "password"
$Data = "nccs.php?startDate=2015-05-31"

Global $hw_open = _WinHttpOpen("WinHTTP Example4")
If @error Then 
    MsgBox(48, "Error", "Error initializing the usage of WinHTTP functions.")
    Exit
EndIf

Global $hw_connect = _WinHttpConnect($hw_open, $URL)
If @error Then 
    MsgBox(48, "Error", "Error specifying the initial target server of an HTTP request.")
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

Global $h_openRequest = _WinHttpOpenRequest($hw_connect, "GET", $Data)
If @error Then 
    MsgBox(48, "Error", "Error creating an HTTP request handle.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpSetCredentials($h_openRequest, $WINHTTP_AUTH_TARGET_SERVER, $WINHTTP_AUTH_SCHEME_BASIC, $username, $password)
If @error Then 
    MsgBox(48, "Error", "Unable to set Credentials.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpSendRequest($h_openRequest)
If @error Then 
    MsgBox(48, "Error", "Error sending the specified request.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

_WinHttpReceiveResponse($h_openRequest)
If @error Then 
    MsgBox(48, "Error", "Error ReceiveResponse.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
    Exit
EndIf

If _WinHttpQueryDataAvailable($h_openRequest) Then
    Global $header = _WinHttpQueryHeaders($h_openRequest)
    If @error Then 
        MsgBox(48, "Error", "Error QueryHeaders.")
        _WinHttpCloseHandle($hw_connect)
        _WinHttpCloseHandle($hw_open)
        Exit
    Endif

    Global $data
    While 1
        $data &= X_WinHttpReadData($h_openRequest)
        If Not @extended Then ExitLoop      
    WEnd

Else 
    MsgBox(48, "Error", "Error QueryDataAvailable.")
    _WinHttpCloseHandle($hw_connect)
    _WinHttpCloseHandle($hw_open)
EndIf

_WinHttpCloseHandle($h_openRequest)
_WinHttpCloseHandle($hw_connect)
_WinHttpCloseHandle($hw_open)

FileWrite ("header.txt", $header)
FileWrite ("data.txt",  $data)

Func X_WinHttpReadData($hRequest, $iNumberOfBytesToRead = 8192)

    Local $lpBuffer = DllStructCreate("char[" & $iNumberOfBytesToRead & "]")

    Local $a_iCall = DllCall("Winhttp.dll", "int", "WinHttpReadData", _
            "hwnd", $hRequest, _
            "ptr", DllStructGetPtr($lpBuffer), _
            "ulong", $iNumberOfBytesToRead, _
            "dword*", 0)
    
    If @error Or Not $a_iCall[0] Then
        SetError(1, 0, "")
    EndIf
    
    Return SetError(0, $a_iCall[4], DllStructGetData($lpBuffer, 1))
    
EndFunc

The Header.txt contains:

HTTP/1.1 400 Bad Request
Date: Tue, 02 Jun 2015 20:24:06 GMT
Server: Apache/2.2.29 (Amazon)
Vary: Accept-Encoding
Content-Length: 449
Connection: close
Content-Type: text/html; charset=iso-8859-1

And the Data.txt contains:

nccs.php?startDate=2015-05-31<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
 Instead use the HTTPS scheme to access this URL, please.<br />
</p>
<hr>
<address>Apache/2.2.29 (Amazon) Server at example.com Port 443</address>
</body></html>

Any suggestions and help would be greatly appreciated!

-Marc

​You could let WinHttp.au3 do all the job internally for you through _WinHttpSimpleFormFill. Like this maybe:

#include "WinHttp.au3"

$sAddress = "https://www.example.com/admin/report.php" ; the address of the target
$sUserName = "username"
$sPassword = "password"
$sDate = "2015-05-31"

$sForm = _
        '<form action="' & $sAddress & '" method="get">' & _
        '    <input name="startDate"/>' & _ ;
        '</form>'

; Initialize and get session handle
$hOpen = _WinHttpOpen()

$hConnect = $sForm ; will pass form as string so this is for coding correctness because $hConnect goes in byref



; Fill form
$sHTML = _WinHttpSimpleFormFill($hConnect, $hOpen, _
        Default, _
        "name:startDate", $sDate, _
        "[CRED:" & $sUserName & "," & $sPassword & "]")

If @error Then
    MsgBox(4096, "Error", "Error number = " & @error)
Else
    ConsoleWrite($sHTML & @CRLF)
    MsgBox(4096, "Returned", $sHTML)
EndIf



; Close handles
_WinHttpCloseHandle($hConnect)
_WinHttpCloseHandle($hOpen)

 

Edited by trancexx
eng

♡♡♡

.

eMyvnE

Posted

​_WinHttpSimpleSendSSLRequest will close request handle and return 0 in case of error (including cert errors). That's why you can't do anything with it.

 I don't know what version of WinHttp.au3 you use, but some time ago I added new parameter for _WinHttpSimpleSendSSLRequest to be able to ignore cert errors. This parameter is used internally when needed, so it's not documented. Anyway, if you want you can use it like this:

$hHTTPrequest = _WinHttpSimpleSendSSLRequest($hHTTPconnect, Default, $sQueryData, Default, Default, Default, True)

... to make request ignoring cert errors.

Btw, why do you query security flags? Who cares what they are. If you want to ignore cert errors just set flags you want.

 

​Thank you for your reply trancexx.  

I was able to get it to go using the undocumented parameter for ignoring all cert errors.

The reason for querying the security flags and modifying them was as a result of reviewing some other posts and MSDN examples.  Now that you mention it, I think you're absolutely right that I don't need to do the query, and could simply set the flags I want going forward.

Thank you again,
bPi

Posted

trancexx,

​You could let WinHttp.au3 do all the job internally for you through _WinHttpSimpleFormFill. Like this maybe:

Thank you, thank you - in my ignorance I would never have thought to use the formfill function. Yet now after seeing it work and thinking about, it's beginning too make sense. I'm going to play with it some more - but it did get me exactly what I wanted!

So thank you for help and for writing WinHTTP.au3 in the first place!

-Marc

  • 3 weeks later...
Posted

To get extensions info you should query for $WINHTTP_OPTION_SERVER_CERT_CONTEXT and then use Certificate functions to read data.
Something like this (no error checking here):
 

#include "WinHttp.au3"

$hOpen = _WinHttpOpen()
$hConnect = _WinHttpConnect($hOpen, "https://www.facebook.com")
$hRequest = _WinHttpSimpleSendSSLRequest($hConnect)

; Query for CERT_CONTEXT pointer
$tBuffer = DllStructCreate("ptr")
DllCall($hWINHTTPDLL__WINHTTP, "bool", "WinHttpQueryOption", _
  "handle", $hRequest, _
  "dword", $WINHTTP_OPTION_SERVER_CERT_CONTEXT, _
  "struct*", $tBuffer, _
  "dword*", DllStructGetSize($tBuffer))

ConsoleWrite("> CERT_CONTEXT pointer: " & DllStructGetData($tBuffer, 1) & @CRLF)

; Close handles
_WinHttpCloseHandle($hRequest)
_WinHttpCloseHandle($hConnect)
_WinHttpCloseHandle($hOpen)


$pContext = DllStructGetData($tBuffer, 1)

Const $CERT_NAME_DNS_TYPE = 6
Const $CERT_NAME_SEARCH_ALL_NAMES_FLAG = 0x2

; Read size of the needed buffer
$aCall = DllCall("Crypt32.dll", "dword", "CertGetNameString", _
        "ptr", $pContext, _
        "dword", $CERT_NAME_DNS_TYPE, _
        "dword", $CERT_NAME_SEARCH_ALL_NAMES_FLAG, _
        "dword*", 0, _
        "struct*", 0, _
        "dword", 0)
$iSize = $aCall[0]

; Create buffer
$tStruct = DllStructCreate("byte[" & $iSize & "]")

; Read DNS names
$aCall = DllCall("Crypt32.dll", "dword", "CertGetNameString", _
        "ptr", $pContext, _
        "dword", $CERT_NAME_DNS_TYPE, _
        "dword", $CERT_NAME_SEARCH_ALL_NAMES_FLAG, _
        "dword*", 0, _
        "struct*", $tStruct, _
        "dword", $iSize)

; Free CERT_CONTEXT
DllCall("Crypt32.dll", "dword", "CertFreeCertificateContext", "ptr", $pContext)

; Split on NULL character and convert to array
$aArr = StringSplit(BinaryToString(DllStructGetData($tStruct, 1)), Chr(0), 2)

ConsoleWrite("Subject Alternative Name - DNS Name=" & @CRLF)
For $i = 0 To UBound($aArr) - 1
    ConsoleWrite(@TAB & $aArr[$i] & @CRLF)
Next

 

...Sorry for not replying earlier.

So many thanks for your reply!

I tried your code and got DNS name from Subject Alternative Name.But it seems this code only return the first DNS name while some site's certificate contain many alternative DNS names.Currently I simply use getpeercert() in Python to get the SubjectAltName info,but how can I get the full list of all DNS names using Autoit?

Thanks again.

Posted

Please stop quoting the whole code (already posted) without reason. I can assure you that trancexx knows very well what and why she posted and BTW her post is still there for reference. Doing so only makes the discussion uselessly lengthy and increases the load on the AutoIt server with no purpose.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Posted

So many thanks for your reply!

I tried your code and got DNS name from Subject Alternative Name.But it seems this code only return the first DNS name while some site's certificate contain many alternative DNS names.Currently I simply use getpeercert() in Python to get the SubjectAltName info,but how can I get the full list of all DNS names using Autoit?

Thanks again.

That code snippet should give you exactly what you want. For me it prints:

Subject Alternative Name - DNS Name=
    *.facebook.com
    facebook.com
    *.fb.com
    fb.com
    *.fbsbx.com
    *.fbcdn.net
    *.xx.fbcdn.net
    *.xy.fbcdn.net
    *.xz.fbcdn.net
    *.m.facebook.com
    *.messenger.com
    messenger.com

Could you show me your console output for the exact code I posted? Also what system you run the code on? And with what version of both AutoIt and WinHttp.au3?

♡♡♡

.

eMyvnE

Posted

Please stop quoting the whole code (already posted) without reason. I can assure you that trancexx knows very well what and why she posted and BTW her post is still there for reference. Doing so only makes the discussion uselessly lengthy and increases the load on the AutoIt server with no purpose.

I couldn't disagree more with you on the subject. It's only polite to quote the post you are directly replying to, unless it's the last post in which case it's up to poster to decide what's best. That's how forums are meant to be used and how references are referenced. Forums have "Quote" button for reason. Additionally some posters tend to edit/delete their posts even after being quoted for whatever reason (usually dumb type of such), that'd be resulting in completely broken discussions if your "advice" would be followed..
Excuse me for saying this but your argument about the server load is nothing more than unnecessary additional server load :).

♡♡♡

.

eMyvnE

Posted

Sorry to disagree but I stand by. Over & out.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Posted

That code snippet should give you exactly what you want. For me it prints:

Subject Alternative Name - DNS Name=
    *.facebook.com
    facebook.com
    *.fb.com
    fb.com
    *.fbsbx.com
    *.fbcdn.net
    *.xx.fbcdn.net
    *.xy.fbcdn.net
    *.xz.fbcdn.net
    *.m.facebook.com
    *.messenger.com
    messenger.com

Could you show me your console output for the exact code I posted? Also what system you run the code on? And with what version of both AutoIt and WinHttp.au3?

Hi trancexx,thanks for your help.

My system: Win 7 professional SP1 X64 English version with Chinese support(I'm in China)

Autoit version: 3.3.12.0.

WinHttp.au3: 1.6.3.7

Below is the console output:

>"C:\Program Files (x86)\AutoIt3\SciTE\AutoIt3Wrapper\AutoIt3Wrapper.exe" /run /prod /ErrorStdOut /in "C:\Users\jxc3358\Desktop\chrome\SubjectAltName.au3" /UserParams    
+>09:08:57 Starting AutoIt3Wrapper v.15.503.1200.1 SciTE v.3.5.4.0   Keyboard:00000804  OS:WIN_7/Service Pack 1  CPU:X64 OS:X64    Environment(Language:0409)
+>         SciTEDir => C:\Program Files (x86)\AutoIt3\SciTE   UserDir => C:\Users\jxc3358\AppData\Local\AutoIt v3\SciTE\AutoIt3Wrapper   SCITE_USERHOME => C:\Users\jxc3358\AppData\Local\AutoIt v3\SciTE 
>Running AU3Check (3.3.12.0)  from:C:\Program Files (x86)\AutoIt3  input:C:\Users\jxc3358\Desktop\chrome\SubjectAltName.au3
+>09:08:57 AU3Check ended.rc:0
>Running:(3.3.12.0):C:\Program Files (x86)\AutoIt3\autoit3.exe "C:\Users\jxc3358\Desktop\chrome\SubjectAltName.au3"    
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
> CERT_CONTEXT pointer: 0x00ACE128
Subject Alternative Name - DNS Name=
    *.facebook.com
    
+>09:09:00 AutoIt3.exe ended.rc:0
+>09:09:00 AutoIt3Wrapper Finished.
>Exit code: 0    Time: 3.147

 

Posted

Ah yes, option to list all was added with win8. On your system it's not possible to list all entries using underlying function. Did you search around the web to see how to do it on pre-win8 systems?

♡♡♡

.

eMyvnE

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...