0

I am writing a small client application that will poll the IP camera using the ONVIF protocol but Ifaced with the issue. Need to use only C ++, without using gSOAP tools.

I use examples from this link Onvif programmers guide

Cameras that are not password protected and therefore do not require the generation of data for authorization, respond correctly. The problem I faced is the forming of data for authorization.

When sending any request to the camera (for example, GetProfiles), the camera always responds with 400 errors. Here is an example request:

POST /onvif/Media_service HTTP/1.1
Connection: keep-alive
Content-Length: 948
Content-Type: application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/media/wsdl/GetProfiles"
Host: 192.168.10.205
User-Agent: gSOAP/2.8

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <s:Header>
       <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <UsernameToken>
            <Username>admin</Username>
                <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">M2IzYWYyOGE5OWE3ZDk3NGYzMGU1MzlkZWVhMDYyODMxMmU3NDIxMA==</Password>
                <Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MTIzNDU2Nzg5</Nonce>
                <Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2019-03-16T10:43:18Z</Created>
            </UsernameToken>
      </Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl"/>
    </s:Body>
</s:Envelope> 

Here is an example of the camera response:

HTTP/1.1 400 Bad Request
Server: gSOAP/2.8
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 1212
Connection: close


<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope > // I skipped the listing of the namespace
    <SOAP-ENV:Header>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
    <SOAP-ENV:Code>
        <SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
        <SOAP-ENV:Subcode>
            <SOAP-ENV:Value>ter:NotAuthorized</SOAP-ENV:Value>
        </SOAP-ENV:Subcode>
    </SOAP-ENV:Code>
    <SOAP-ENV:Reason>
        <SOAP-ENV:Text xml:lang="en">Sender not Authorized</SOAP-ENV:Text>
    </SOAP-ENV:Reason>
    <SOAP-ENV:Detail>The action requested requires authorization and the sender is not authorized.</SOAP-ENV:Detail>
        </SOAP-ENV:Fault>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

According to point "6.1.1.3" from the documentation above, need to create a "Digest" as follows:

Digest = B64ENCODE( SHA1( B64DECODE( Nonce ) + Date + Password ) )

In my code, the functions B64DECODE, SHA1, and B64ENCODE work correctly, checked by comparing with various online generators.

I tried to set the Nonce parameter differently. So far, all to no avail. As i guessthe error lies precisely in the work with the parameter that I send to the SHA1() function, but I can be wrong.

Can anyone say what could be the cause of the error?

I post not all the code, but only the part that is related to the formation of the necessary data.

I would be grateful for any help.

CODE:

// hardcoded nonce
char caNonceTest[20] = { 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38 };
caNonceTest[19] = '\0';

// Random generaterd nonce
//char caNonceTest[SHA_DIGEST_LENGTH];
//int nonceInt = rand();

//memset(caNonceTest, 1, SHA_DIGEST_LENGTH);
//memcpy(caNonceTest, &nonceInt, sizeof(nonceInt));


// Get data/time
string sDataUTC = currentISO8601TimeUTC();

// non-crypted password. Make function to get password from user
string sPass = "admin";
string sName = "default";

string sNonce(caNonceTest);

// temp string for SHA1
string sTempSumBin = (sNonce) + /*string2bin*/(sDataUTC)+ /*string2bin*/(sPass); // with string2bin it is also not working


unsigned char digest[SHA_DIGEST_LENGTH];

char cstr[sTempSumBin.size() + 1];
strcpy(cstr, sTempSumBin.c_str());

SHA1((unsigned char*)&cstr, strlen(cstr), (unsigned char*)&digest);

char cSHA1Pass[SHA_DIGEST_LENGTH * 2 + 1];

for (int i = 0; i < SHA_DIGEST_LENGTH; i++)
    sprintf(&cSHA1Pass[i * 2], "%02x", (unsigned int)digest[i]);
printf("SHA1 string before : %s \n", cSHA1Pass);

string strTob64(cSHA1Pass);
string strFinishedPAss = base64_encode(strTOb64); // this is the final result of the password
AlexVenkov
  • 1
  • 1
  • 1
  • check https://stackoverflow.com/a/50346735/795910 – Ottavio Campana Apr 08 '19 at 10:24
  • 2
    Also, check the camera date / time, if it is very far off the time on the client (which may happen if the camera is not set up with NTP) the auth will be rejected since the camera will assume spoofing. I've seen such cases:) – Rudolfs Bundulis Apr 08 '19 at 18:26

0 Answers0