0

I'm struggling with implementing WS-Security in Progress ABL.

It seems possible, this knowledgebase: http://knowledgebase.progress.com/articles/Article/P88147 states:

  • For outgoing WS-Security, create SOAP Headers containing the WS-Security content manually using the OpenEdge Web Service client.

First of all I'm struggling with the creation of a base64 encoded and SHA1 digested password hash.

Password digest according to the WS-Security specification. Source.

Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) ) 

Nonce is a random string of a specific length, could basically be a UUID. The nonce is Base64-encoded (it's sent encoded in the soap header).

Created is a date in the format "YYYY-MM-DDTHH:MM:SS.SSSZ". Milliseconds are optional. Z for GMT should always be set.

Password is a password given out by the web service provider.

Trying to mimic this answer on SO: Working algorithm for PasswordDigest in WS-Security

PROCEDURE generatePassHash:
    DEFINE INPUT  PARAMETER pcNonce    AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcCreated  AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcPassword AS CHARACTER   NO-UNDO.

    DEFINE OUTPUT PARAMETER pcHash     AS CHARACTER   NO-UNDO.

    DEFINE VARIABLE mBytes        AS MEMPTR      NO-UNDO.
    DEFINE VARIABLE cNonceDecoded AS CHARACTER   NO-UNDO.

    /* Base64-decode the nonce since it's in encoded format */
    ASSIGN 
        cNonceDecoded = STRING(BASE64-DECODE(pcNonce)).

    /* Set size of mempointer */
    SET-SIZE(mBytes) = LENGTH(cNonceDecoded) + LENGTH(pcCreated) + LENGTH(pcPassword) + 1.

    /* Put the decoded nonce first */
    PUT-STRING(mBytes, 1) = cNonceDecoded.

    /* Add create time */
    PUT-STRING(mBytes, 1 + LENGTH(cNonceDecoded)) = pcCreated.

    /* Add password */
    PUT-STRING(mBytes, 1 + LENGTH(cNonceDecoded) + LENGTH(pcCreated)) = pcPassword.

    /* Create out-data */
    pcHash = STRING(BASE64-ENCODE(SHA1-DIGEST(mBytes))).

    /* Clean up mempointer */
    SET-SIZE(mBytes) = 0.


END PROCEDURE.

DEFINE VARIABLE cNonce       AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cTimeStamp   AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cClearPass   AS CHARACTER   NO-UNDO.
DEFINE VARIABLE cRightAnswer AS CHARACTER   NO-UNDO.

ASSIGN
    cNonce       = "UIYifr1SPoNlrmmKGSVOug=="
    cTimeStamp   = "2009-12-03T16:14:49Z"
    cClearPass   = "test8"
    cRightAnswer = "yf2yatQzoaNaC8BflCMatVch/B8=".

RUN generatePassHash(cNonce, cTimeStamp, cClearPass, OUTPUT cHash).

MESSAGE "Is:" SKIP cHash SKIP(2)
    "Should be:" SKIP
    cRightAnswer
    VIEW-AS ALERT-BOX INFORMATION TITLE "OK?".

I'm guessing that this might have to do with either me messing up the mempointer handling or the fact that everything should be UTF-8?

NB

I can easily produce the same erroneous hash as mentioned in the referenced question above with this simple code:

MESSAGE STRING(BASE64-ENCODE(SHA1-DIGEST("UIYifr1SPoNlrmmKGSVOug==" + "2009-12-03T16:14:49Z" + "test8"))) VIEW-AS ALERT-BOX
Community
  • 1
  • 1
Jensd
  • 7,886
  • 2
  • 28
  • 37

1 Answers1

1

PUT-STRING will, if no length is specified, put a NULL terminated string into your MEMPTR - which is why you needed to set the length to + 1 - which was the wrong solution to 'Can't PUT past the end of the MEMPTR. (4791)'

Remove + 1 from SET-SIZE and change password to:

PUT-STRING(mBytes, 1 + LENGTH(cNonceDecoded) + LENGTH(pcCreated), LENGTH(pcPassword)) = pcPassword.

Stefan Drissen
  • 3,266
  • 1
  • 13
  • 21
  • Works like a charm! I had an idea it was something like this and I recall that NULL has bitten me before... – Jensd Oct 01 '14 at 05:47
  • However, it doesn't work on other examples I've received. Like this one: `ASSIGN cNonce = "VVBXZ0xIVW4=" cTimeStamp = "2014-10-01T07:20:26:660Z" cClearPass = "AMADEUS" cRightAnswer = "OljgJAghr3NZdXJaQNPRCbJg+XE=".` It produces another hash (bLj...). Might have to do with different formats (base64 etc) of the input data perhaps? – Jensd Oct 01 '14 at 10:42
  • 1
    If I have understood it correctly, the timestamp can be formatted however you like, as long as you are consistent - but 07:20:26:660Z looks odd - shouldn't that be 07:20:26.660Z? How are you sure that the example you have received /is/ correct? – Stefan Drissen Oct 01 '14 at 20:40
  • Good point. I didn't see that last colon. Changing it doesn't give me a better result though. I cannot be 100% sure the examples I've recieved are correct but at this point I trust them more than my own algorithm... – Jensd Oct 02 '14 at 06:09
  • I just tried a soapUI generated one (see http://www.soapui.org/SOAP-and-WSDL/applying-ws-security.html for how to configure) - works fine. ASSIGN cNonce = "ByduiuimrJgTaJvn/dE2NQ==" cTimeStamp = "2014-10-02T21:07:32.632Z" cClearPass = "AMADEUS" cRightAnswer = "bwiAWNgKf3Lz5Tir7IuDtKiTMT0=". – Stefan Drissen Oct 02 '14 at 21:12