Read the https body in SWI-Prolog

One more question from me .. Overall I was trying to define authenticate_alexa/1

.

This (I think) provides the same functionality as this java code from amazon: https://github.com/amzn/alexa-skills-kit-java/blob/master/src/com/amazon/speech/speechlet /authentication/SpeechletRequestSignatureVerifier.java

Instructions on what to do is: https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/developing-an-alexa-skill-as-a-web-service

Now the problem is that I need to read the full httpsbody request and find its hash value to check if it works with the key from the chain we received. (Step 7 signature verification).

So I need to define httpsbody/2

which one will return the body exactly and then have the correct code to validate the hash values.

My current code:

alexa(Request):-
    authenticate_alexa(Request),
    %http_read_json_dict(Request,DictIn),
    %handle_dict(DictIn,DictOut),
    my_json_answer(hello,DictOut),
    reply_json(DictOut).

authenticate_alexa(Request):-
    check_sigchainurl(Request,URL),
    portray_clause(user_error,URL),
    get_certs(URL,[ACert|CertsRest]),
    checkcertvalid_time(ACert),
    checkchain([ACert|CertsRest]),
    memberchk(key(Key),ACert),
    base64decodesig_encryptedSig(Request,ESig),
%   httpsbody(Request,Body), %how do we read the body of the request?
        httpsbodybytes(Request,Body),
        portray_clause(user_error,'Http Body from httpsbody(Request,Body) :'),
        portray_clause(user_error,Body),
    crypto_data_hash(Body,Hash,[algorithm(sha1),encoding(octet)]),
    portray_clause(user_error,'Serviced signed Hash:'),
    portray_clause(user_error,Hash),
        atom_string(Hash,HashString),
    string_concat("0x",HashString,HashString2),
    number_string(HashNumber,HashString2),
    portray_clause(user_error,'Hash as Dec'),
    portray_clause(user_error,HashNumber),

    signature_pow(ESig,0x010001,Key,ClpfdHash),
    portray_clause(user_error,'clpfdhash:'),
    portray_clause(user_error,ClpfdHash),
        %rsa_verify(Key,Hash,ESig,[type(sha1)]),
    portray_clause(user_error,done).

get_certs(URL,Certs):-
   setup_call_cleanup(
        http_open(URL,Stream,[]),
        ssl_peer_certificate_chain(Stream,Certs),
        close(Stream)
          ).

signature_pow(Sig, Exp, P, Pow) :-
        portray_clause(user_error,'ESig:'),
    portray_clause(user_error,Sig),
    (atom(Sig) -> portray_clause(user_error,'it is an atom');portray_clause(user_error,'it is not an atom')),
    (number(Sig) -> portray_clause(user_error,'it is a number');portray_clause(user_error,'it is not a number')),
    atom_string(Sig,Sigstring),
    string_concat("0x",Sigstring,SigString2),
    number_string(SigNumber,SigString2),
    portray_clause(user_error,'Exp:'),
    portray_clause(user_error,Exp),
    portray_clause(user_error,'P:'),
    portray_clause(user_error,P),
    P =public_key(rsa(P2,EXP2,_,_,_,_,_,_)),
    portray_clause(user_error,'P just number:'),
        portray_clause(user_error,P2),
    (string(P2) -> portray_clause(user_error,'String hex P number');portray_clause(user_error,notstring)),
    string_concat("0x",P2,NewString),
    portray_clause(user_error,NewString),
    number_string(P3,NewString),
    portray_clause(user_error,'P number as dec:'),
    portray_clause(user_error,P3),  
        Pow #= SigNumber^Exp mod P3,
    portray_clause(user_error,'Pow'),
    portray_clause(user_error,Pow),
    portray_clause(user_error,verified).

check_sigchainurl(Request,URL):-
    memberchk(signaturecertchainurl(URL),Request),
    parse_url(URL,P), %what about normalise url? I dont think it is needed
    memberchk(protocol(https),P),%should make case insenstive
    memberchk(host('s3.amazonaws.com'),P), %should make case insenstive
    memberchk(path(Path),P),
    string_concat('/echo.api/',_,Path),
    (memberchk(port(Port),P) -> Port =443 ; true).

checkcertvalid_time(Acert):-
    memberchk(notbefore(NotBefore),Acert),
    memberchk(notafter(NotAfter),Acert),
    get_time(NowA),
    Now is round(NowA),
    Now #>NotBefore,
    Now #<NotAfter.

checkchain(Chain):-
        length(Chain,L),
    L#>1.           %Insure chain has more than one cert
    %portray_clause(user_error,Chain),
    checkchain_h(Chain).

checkchain_h([_]). %Reached the root.
checkchain_h(Chain):-
        Chain =[C1,C2|Rest],
        memberchk(signature(Sig),C1),
    memberchk(to_be_signed(Signed),C1),
    memberchk(key(Key),C2),
    hex_bytes(Signed,Bytes),
    crypto_data_hash(Bytes,Hash,[algorithm(sha256),encoding(octet)]),
    rsa_verify(Key,Hash,Sig,[type(sha256)]),
    checkchain_h([C2|Rest]).

base64decodesig_encryptedSig(Request,Hex):-
    memberchk(signature(B64Sig),Request),
    portray_clause(user_error,'base64 encoded sig:'),
    portray_clause(user_error,B64Sig),
    base64(ESig,B64Sig),
    atom_codes(ESig,Bytes),
    hex_bytes(Hex,Bytes).
    %portray_clause(user_error,'Esig is base64 sig decoded using base64//2:'),
    %portray_clause(user_error,ESig).
        %portray_clause(user_error,'Can not print esig').

httpsbodybytes(Request,BodyBytes2):-
    memberchk(input(In),Request),
    portray_clause(user_error,"Bytes:"),
    mygetbody2(In,BodyBytes,0),
    list_butlast(BodyBytes,BodyBytes2).

mygetbody2(_Stream,[],-1).
mygetbody2(Stream,[Byte|Bytes],Check):-
    dif(Check,-1),
    get_byte(Stream,Byte),
    %portray_clause(user_error,Byte),
    mygetbody2(Stream,Bytes,Byte).

list_butlast([X|Xs], Ys) :-                 % use auxiliary predicate ...
   list_butlast_prev(Xs, Ys, X).            % ... which lags behind by one item

list_butlast_prev([], [], _).
list_butlast_prev([X1|Xs], [X0|Ys], X0) :-  
   list_butlast_prev(Xs, Ys, X1).

      

That after receiving the request it gives:

'https://s3.amazonaws.com/echo.api/echo-api-cert-4.pem'.
'base64 encoded sig:'.
'Nu2v3C8hWNSF7G7N/B5WWqFnhuGMPJeMGi76FanbF8D4so+AiRSWVaehPXoaiLZpCiEb5Ysd+QFCBEt5/5a6MoLh4JTAhwGcnGUs+GbZo7rkk12t6meUTldnBNZ4/1boUNGurWCmPy1pkCWyHIt7udWj2zCdHx+4cFCKy8GVWfjOtZ3n52LWzGd+HO0RF0GQ25cSoFQGr2I5bT060Bodt3PrZob/nWnPxqayC+y53Itt/I0YUtM2QnPYByx/GJuyzMUuA0/v0PH15oGOE+wwYszr1C6mmEKMRdkCzFEO6z4kuw6UeXDaECS9ak04XCp+gsYkHQjJYpoB3s8T6qeNGQ=='.
"Bytes:".
'Http Body from httpsbody(Request,Body) :'.
[123, 34, 118, 101, 114, 115, 105, 111, 110, 34, 58, 34, 49, 46, 48, 34, 44, 34, 115, 101, 115, 115, 105, 111, 110, 34, 58, 123, 34, 110, 101, 119, 34, 58, 102, 97, 108, 115, 101, 44, 34, 115, 101, 115, 115, 105, 111, 110, 73, 100, 34, 58, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 46, 99, 55, 99, 54, 49, 55, 51, 100, 45, 98, 98, 102, 52, 45, 52, 56, 57, 101, 45, 97, 48, 98, 97, 45, 52, 54, 55, 102, 101, 56, 48, 51, 100, 97, 101, 99, 34, 44, 34, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 34, 58, 123, 34, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 73, 100, 34, 58, 34, 97, 109, 122, 110, 49, 46, 97, 115, 107, 46, 115, 107, 105, 108, 108, 46, 97, 50, 55, 101, 98, 53, 48, 53, 45, 102, 99, 101, 102, 45, 52, 57, 98, 102, 45, 56, 57, 55, 53, 45, 51, 101, 49, 97, 54, 100, 55, 98, 55, 99, 55, 52, 34, 125, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 58, 123, 125, 44, 34, 117, 115, 101, 114, 34, 58, 123, 34, 117, 115, 101, 114, 73, 100, 34, 58, 34, 97, 109, 122, 110, 49, 46, 97, 115, 107, 46, 97, 99, 99, 111, 117, 110, 116, 46, 65, 71, 77, 77, 80, 53, 85, 81, 73, 81, 80, 89, 52, 69, 75, 90, 90, 72, 88, 71, 68, 52, 86, 72, 55, 89, 72, 80, 55, 88, 65, 51, 54, 84, 65, 79, 50, 82, 54, 76, 87, 79, 77, 89, 73, 88, 75, 78, 52, 68, 72, 88, 88, 51, 66, 73, 83, 53, 87, 83, 82, 78, 84, 53, 65, 55, 86, 79, 75, 86, 82, 76, 50, 77, 75, 65, 78, 77, 86, 51, 75, 50, 68, 77, 79, 66, 50, 87, 75, 85, 68, 84, 72, 73, 74, 86, 87, 73, 77, 83, 65, 51, 76, 81, 75, 82, 73, 73, 83, 72, 71, 55, 80, 71, 55, 77, 89, 70, 65, 53, 50, 72, 77, 73, 67, 81, 87, 53, 53, 76, 50, 73, 90, 65, 76, 70, 90, 80, 77, 82, 54, 67, 74, 83, 74, 54, 74, 55, 90, 82, 75, 54, 54, 77, 87, 82, 55, 66, 89, 88, 69, 76, 66, 73, 50, 75, 79, 69, 90, 81, 73, 72, 68, 88, 79, 72, 72, 90, 70, 71, 90, 50, 81, 83, 90, 82, 87, 52, 75, 55, 79, 55, 53, 82, 50, 89, 88, 74, 54, 85, 87, 65, 86, 70, 77, 53, 65, 34, 125, 125, 44, 34, 114, 101, 113, 117, 101, 115, 116, 34, 58, 123, 34, 116, 121, 112, 101, 34, 58, 34, 73, 110, 116, 101, 110, 116, 82, 101, 113, 117, 101, 115, 116, 34, 44, 34, 114, 101, 113, 117, 101, 115, 116, 73, 100, 34, 58, 34, 69, 100, 119, 82, 101, 113, 117, 101, 115, 116, 73, 100, 46, 101, 54, 98, 56, 102, 101, 101, 100, 45, 101, 99, 101, 51, 45, 52, 101, 97, 97, 45, 97, 102, 50, 100, 45, 99, 52, 55, 102, 54, 53, 55, 53, 57, 50, 49, 54, 34, 44, 34, 116, 105, 109, 101, 115, 116, 97, 109, 112, 34, 58, 34, 50, 48, 49, 55, 45, 48, 54, 45, 49, 57, 84, 48, 57, 58, 52, 54, 58, 51, 53, 90, 34, 44, 34, 108, 111, 99, 97, 108, 101, 34, 58, 34, 101, 110, 45, 71, 66, 34, 44, 34, 105, 110, 116, 101, 110, 116, 34, 58, 123, 34, 110, 97, 109, 101, 34, 58, 34, 103, 101, 116, 65, 78, 101, 119, 70, 97, 99, 116, 34, 125, 125, 125].
'Serviced signed Hash:'.
'64f1329a1f707809174ee50a6df9f65099bba371'.
'Hash as Dec'.
576277964734800966164187927075551858658582963057.
'ESig:'.
'36edafdc2f2158d485ec6ecdfc1e565aa16786e18c3c978c1a2efa15a9db17c0f8b28f8089149655a7a13d7a1a88b6690a211be58b1df90142044b79ff96ba3282e1e094c087019c9c652cf866d9a3bae4935dadea67944e576704d678ff56e850d1aead60a63f2d699025b21c8b7bb9d5a3db309d1f1fb870508acbc19559f8ceb59de7e762d6cc677e1ced11174190db9712a05406af62396d3d3ad01a1db773eb6686ff9d69cfc6a6b20becb9dc8b6dfc8d1852d3364273d8072c7f189bb2ccc52e034fefd0f1f5e6818e13ec3062ccebd42ea698428c45d902cc510eeb3e24bb0e947970da1024bd6a4d385c2a7e82c6241d08c9629a01decf13eaa78d19'.
'it is an atom'.
'it is not a number'.
'Exp:'.
65537.
'String hex P number'.
'P number as dec:'.
23367091749731801702903258951332579149824717752403036738901918995576378221876991769215986117060832205938888292020670601919717320529579897428555756633750717630113812467159229456710215094841206836055184753491046351652384568208399197333334554354625485949013821994244854426626217946383766717620084958916568639573896625634280251135248126961353512501885364402868885624724204807768627558428281558589460261611023934365963620820837651899784648073096603839587883308136461448176498481934437054583664797923342609641294880521414948881981392762983173267396409953920339084175033120756130451537931813023420728016059287928243275252817.
'Pow'.
12996685404671854237337597057543403676067050401691031855263389356566563793267812208256044577937494803172529297811694697178075070962940655950099948830185429064594023055861430145065585159411714852185690089480769442404348006975883315459440182824265725834630838968686976962484449232569444592352993640898180649431183234665232203068528805991370779087967630073792656438871568328046165107095895856647485355472888016164031315511155737623289424119686691313121050647697592969024984185347837785283636035540443593041046047481149874499335289745021686457982828945403796990195913021023926745047308779421759663632404133499645864797253.
verified.
'clpfdhash:'.
12996685404671854237337597057543403676067050401691031855263389356566563793267812208256044577937494803172529297811694697178075070962940655950099948830185429064594023055861430145065585159411714852185690089480769442404348006975883315459440182824265725834630838968686976962484449232569444592352993640898180649431183234665232203068528805991370779087967630073792656438871568328046165107095895856647485355472888016164031315511155737623289424119686691313121050647697592969024984185347837785283636035540443593041046047481149874499335289745021686457982828945403796990195913021023926745047308779421759663632404133499645864797253.
done.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

      

The two hash values ​​do not match. So it is currently not working.

+3


source to share


1 answer


Indicative answer :

I think you are on the right track with read_string/3

, but you need to break this down into a more manageable case so others have a chance to help. For example, add to your question:

  • the complete HTTPS corpus you received
  • the hash you calculated for it
  • the hash that the service signed for it.

I explained how to get the hash that was signed:

fooobar.com/questions/1679467 / ...

See calculation based on CLP (FD).

Note that at the time the connection is established (over TLS) this is purely an HTTP (not HTTPS) layer issue .



Useful predicates :

I see that you are also struggling with the actual Base64 encoded base. To understand this, you can apply the following steps:

  • use base64/2

    to get a simple atom i.e.base64(Plain, Encoded)

  • use atom_codes/2

    to get a list of codes that represent an atom i.e.atom_codes(Plain, Bytes)

  • use from to get the hex encoding of the signature, i.e. ... hex_bytes/2

    library(crypto)

    hex_bytes(Hex, Bytes)

So you get with a useful hexadecimal representation of the signature. You can use this for further computation using CLP (FD) constraints or rsa_verify/4

.

I tried these calculations with your example and I got for Pow #= Sig^Exp mod M

an integer that ends in:

b2feb64cd1ae11365f8917b71bb751142b63f159e12c02a1720b78958c3e7f7e

in hexadecimal system. This is not the hash you calculated. Therefore, there may be a problem with the encoding you are using to compute your own hash of the signature verification data. See Values ​​for crypto_data_hash/3

. In particular, I recommend crypto_data_hash(Bytes, Hash, [encoding(bytes)])

where you should make sure that Bytes

is the actual list of bytes representing the data transferred.

+2


source







All Articles