HttpSignature with rsa-sha256

Hi team,

I'm working on http signatures, based on this development: https://github.com/apigee/iloveapis2015-hmac-httpsignature/tree/master/httpsig/callout

Now, no matter what I'm doing, I always get this error:

{
 "error": "the signature is malformed ()"
}

I'm using simple proxy flow, that contains:

1. PreFlow:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="Java-ParseHttpSignature">
    <Properties/>
    <ClassName>com.google.apigee.callout.httpsignature.SignatureParserCallout</ClassName>
    <ResourceURL>java://edge-custom-httpsig-1.0.2.jar</ResourceURL>
</JavaCallout>

This will take the Signature header and parse it, which it does well.

2. I have some proxy path, like /rsa-t2, and there I have two policies:

a. Pulls out my public key from KVM:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="getkey" mapIdentifier="keys">
    <DisplayName>getkey</DisplayName>
    <Properties/>
    <ExclusiveCache>false</ExclusiveCache>
    <ExpiryTimeInSecs>300</ExpiryTimeInSecs>
    <Get assignTo="pkey">
        <Key>
            <Parameter>signer</Parameter>
        </Key>
    </Get>
    <Scope>environment</Scope>
</KeyValueMapOperations>

.. and this is the key (key from example folder ~ key2-public.pem:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9htfJRKA3EEbvmvrqKON
CGSDHYH3bJffNeca1sqvSN8uA2r16qabG5n21kvOZuzYr6gsK1Qpi870vELbir00
xybyXTJKDjXsSTO+hSVa+bmr8V+ncAJr8ZkyWjPDYufGAsXqbLbUVWAbtiyCbgdA
YBktWwXthQdz867l1ow21ZgR+vwzSDAAg8rK6PGIxqZ+7iVIUMW9eGJpr5vSdRXX
Oushgcr84EBs7TH+0Pzw+rV2PRjD9gpyFvX/JMzx3UaJNscPEdne9wtuolk6VJpS
KPTKTaXinS0grYvSUeY8+qmli20btNiaJ2La+giYAuPMiL99iStmlj+pTgnuVY65
JQIDAQAB
-----END PUBLIC KEY-----

b. JavaCallout for signature parsing:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="Java-VerifyHttpSignature1">
    <Properties>
        <Property name="algorithm">rsa-sha256</Property>
        <Property name="public-key">{pkey}</Property>
    </Properties>
    <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
    <ResourceURL>java://edge-custom-httpsig-1.0.2.jar</ResourceURL>
</JavaCallout>

Now, at this level I expect that my signature will be valid.

I'm singing the content with online signature service (if needed, I can provide link)

I'm singing the content with corresponding privatekey from example folder: key2-private.pem:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA9htfJRKA3EEbvmvrqKONCGSDHYH3bJffNeca1sqvSN8uA2r1
6qabG5n21kvOZuzYr6gsK1Qpi870vELbir00xybyXTJKDjXsSTO+hSVa+bmr8V+n
cAJr8ZkyWjPDYufGAsXqbLbUVWAbtiyCbgdAYBktWwXthQdz867l1ow21ZgR+vwz
SDAAg8rK6PGIxqZ+7iVIUMW9eGJpr5vSdRXXOushgcr84EBs7TH+0Pzw+rV2PRjD
9gpyFvX/JMzx3UaJNscPEdne9wtuolk6VJpSKPTKTaXinS0grYvSUeY8+qmli20b
tNiaJ2La+giYAuPMiL99iStmlj+pTgnuVY65JQIDAQABAoIBAFVRp+pyP7ob2EJr
p4cPLBV8wve31s8O15MYS3WrTpk0xf7pVdfDaoJnHeus3CFSesxqwOVEiCKv3Khn
hTTT4zgniF5G0OWcTA4UojgGe0OX2sQTJTjvnfxj39DloRbowvyzIFIQEAyJBRJi
29TJLsgh8ldb9rvnmYshVwzKDzh8ka92uv2y4Ggnc2yCGXAS1nCANUv6zB/SRoq0
hID7rbLMIO4oC6SqThWZ9IrLFcyiJR1Exs8/Wsjib7CKMtSnFJwBGiz0QVm5ZG0G
zYaF5rl0kHEfO/nqoa5GWUaaWBuRqxYUgKuzTaifqH4ieRXK7vC+80Y5/fAPQ7oq
dvTXGAECgYEA/0rC3ZH4wbWnHbynsxjo/NWjBi7iJUxaLMndeSy9q0sR2y2kZfiE
/qDxRevM+gfLNx3i3LI6g2/gkDbQ6BvnopxihRf3kAIAG2KeAjH3+cA+cuHC2KrO
9kh12zePoDSaZbeIMllIwDFOpHJEOlGSSzTA17ngrj4KgIX85CcKYW0CgYEA9soW
9qdGxVnzDNuj6JVxt2vnguV+XXX3OD5/cHoZoPT3VvqhQDoNyeHLyREuJ7fflxsi
BsTTEHPqP9eyzkZ8uSMphGjGYkUmBxkGRyD5F4POv49n8GyGPN0QHHSeYQinVQN+
QVU1EHPD+Z64NKzyQ1whk7kl5U0980/Sy8/kG5kCgYEA+Qk6HKC39Gc61cRiJ1Dm
fzX8aRy1GMNpuAVX2kwt3fpGOfRFSf/r5OSlWJsVAtc1gtfRpY7ri6pIewYuNi56
gONjLAhcRIvfBNfn4aZTC7xgbvsScv/1EsVOywFhR1vpPc6SuuLkGDBBUiPxsJ5A
QsL8V7UIm5ED96o9L2dyNeUCgYEA68dVux9DsQbn+8/YQDyPIXN5Awjo+rfakqS7
MqWk2K9Ro4reBjOwusD75kSAuTel6YLltlvTXrOwCIC2dvbG8EZUwwkrB/YSh9Nz
uP8anEm0fDWxUvUMJxf47YbJTeFrpQAqXpbelLJVeKYYTVMyPgLGnZDVUMbEOjJ4
LXqX73kCgYBRHMHQ6RXyTMvPy58dbicCiXIDIN7Zf1eB4qONuhJTXT6m1fOyUAQF
LauLv1+9rBA8Cy2aBvOW5FyJ1jFJ9qG43JYc7i6O1NdlM/hUAcAm/8v6Gsgd6w7Q
+v1Nz0cBMYJA4cqLFzuYE3bGIDeyTAxULt/V6CIL2w9LKcmFeQ0O0Q==
-----END RSA PRIVATE KEY-----

...and this is my signed header

user: denis

Now, to wrap all up:

- sending get request to my endpoint with headers:

Signature: keyId="Test",algorithm="rsa-sha256",headers="user", signature="DH7DFavH1j76Hk4oiqTW1hAcmfLHq/1NcFZbgzvtJuLyber7mnih0jBRbvqe7iI34pi6PNZhXLnzvSm6y3e966n4q/yVWwA7Eb17hSkcwcFEiZvzThpM2zjWxRe5fdY3DvjGolBFQJZryx2eF2XzhVS0SowbyWJ/V+bf2GXYF5WvY/3NZczH6X6k58BAdv1Bl7CY0N0LrMbKdCWBDjFCU891B0RzgqaK9XX0z839Lscj6zsTkUh+PzGYvdrLi0CyI36pGUSEzhT/lY2StHR6MFimnXiOc1Y1U0rHnpI09659WDPLPwcCOenQgW4LxsbwQJQ795yJhiGRrRphfqeycg=="
user: denis

And I always get error that signature malformed. What's wrong with my configuration? Validation on online site where I sign the content are valid, in this development - not. I though my keyid is not corresponding to actual public key, but from my understanding this keyId param not important, but I tried to put there serial number of my public key, sha, etc. Never works

Any help will be highly appreciated!

Thanks,

D

Solved Solved
1 19 1,845
1 ACCEPTED SOLUTION

Hi Denis,

I don't know what's going on with your test, but when I test your signature, it works for me.

The request looks like this:

curl -i https://$ORG-$ENV.apigee.net/denis-http-sig/t1 
  -H user:denis  
  -H 'Signature: keyId="testKey",
        algorithm="rsa-sha256",
        headers="user",
        signature="DH7DFavH1j76Hk4oiqTW1hAcmfLHq/1NcFZbgzvtJuLyber7mnih0jBRbvqe7iI34pi6PNZhXLnzvSm6y3e966n4q/yVWwA7Eb17hSkcwcFEiZvzThpM2zjWxRe5fdY3DvjGolBFQJZryx2eF2XzhVS0SowbyWJ/V+bf2GXYF5WvY/3NZczH6X6k58BAdv1Bl7CY0N0LrMbKdCWBDjFCU891B0RzgqaK9XX0z839Lscj6zsTkUh+PzGYvdrLi0CyI36pGUSEzhT/lY2StHR6MFimnXiOc1Y1U0rHnpI09659WDPLPwcCOenQgW4LxsbwQJQ795yJhiGRrRphfqeycg=="'

The Java policy is configured like this:

<JavaCallout name='Java-VerifyHttpSignature-RSA1'>
  <Properties>
    <Property name='algorithm'>rsa-sha256</Property>
    <Property name='headers'>user</Property>
    <Property name='public-key'>
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9htfJRKA3EEbvmvrqKON
CGSDHYH3bJffNeca1sqvSN8uA2r16qabG5n21kvOZuzYr6gsK1Qpi870vELbir00
xybyXTJKDjXsSTO+hSVa+bmr8V+ncAJr8ZkyWjPDYufGAsXqbLbUVWAbtiyCbgdA
YBktWwXthQdz867l1ow21ZgR+vwzSDAAg8rK6PGIxqZ+7iVIUMW9eGJpr5vSdRXX
Oushgcr84EBs7TH+0Pzw+rV2PRjD9gpyFvX/JMzx3UaJNscPEdne9wtuolk6VJpS
KPTKTaXinS0grYvSUeY8+qmli20btNiaJ2La+giYAuPMiL99iStmlj+pTgnuVY65
JQIDAQAB
-----END PUBLIC KEY-----
    </Property>
  </Properties>
  <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
  <ResourceURL>java://edge-custom-httpsig-20200320.jar</ResourceURL>
</JavaCallout>

And the signature verifies.

I've enclosed a working API Proxy here. Can you try it?

apiproxy-denis-http-sig.zip

I've updated the Java callout to version 20200320, but I didn't actually change anything in the behavior. I re-factored the code a little and cleaned things up. I introduced a test for THIS particular case. It's a new JAR, but the old JAR should also work fine.

Looking again at YOUR Java verifier policy.

<JavaCallout name="Java-VerifyHttpSignature1">
    <Properties>
        <Property name="algorithm">rsa-sha256</Property>
        <Property name="public-key">{pkey}</Property>
    </Properties>
    <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
    <ResourceURL>java://edge-custom-httpsig-1.0.2.jar</ResourceURL>
</JavaCallout>

...I notice that you don't specify the 'headers' property. If you specify nothing , hmmmm.... I had not documented this edge case previously, but the designed behavior is that policy verifies just the date header. I have now updated the README with that information.

It would be insecure to just the inbound signature to specify the headers that must be signed; the set of headers must be explicitly enforced in some way on the receiving (verifying) side.

View solution in original post

19 REPLIES 19

Denis, I can look in a few moments.

Sure Dino, any help highly appreciated!

Hi Denis,

I don't know what's going on with your test, but when I test your signature, it works for me.

The request looks like this:

curl -i https://$ORG-$ENV.apigee.net/denis-http-sig/t1 
  -H user:denis  
  -H 'Signature: keyId="testKey",
        algorithm="rsa-sha256",
        headers="user",
        signature="DH7DFavH1j76Hk4oiqTW1hAcmfLHq/1NcFZbgzvtJuLyber7mnih0jBRbvqe7iI34pi6PNZhXLnzvSm6y3e966n4q/yVWwA7Eb17hSkcwcFEiZvzThpM2zjWxRe5fdY3DvjGolBFQJZryx2eF2XzhVS0SowbyWJ/V+bf2GXYF5WvY/3NZczH6X6k58BAdv1Bl7CY0N0LrMbKdCWBDjFCU891B0RzgqaK9XX0z839Lscj6zsTkUh+PzGYvdrLi0CyI36pGUSEzhT/lY2StHR6MFimnXiOc1Y1U0rHnpI09659WDPLPwcCOenQgW4LxsbwQJQ795yJhiGRrRphfqeycg=="'

The Java policy is configured like this:

<JavaCallout name='Java-VerifyHttpSignature-RSA1'>
  <Properties>
    <Property name='algorithm'>rsa-sha256</Property>
    <Property name='headers'>user</Property>
    <Property name='public-key'>
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9htfJRKA3EEbvmvrqKON
CGSDHYH3bJffNeca1sqvSN8uA2r16qabG5n21kvOZuzYr6gsK1Qpi870vELbir00
xybyXTJKDjXsSTO+hSVa+bmr8V+ncAJr8ZkyWjPDYufGAsXqbLbUVWAbtiyCbgdA
YBktWwXthQdz867l1ow21ZgR+vwzSDAAg8rK6PGIxqZ+7iVIUMW9eGJpr5vSdRXX
Oushgcr84EBs7TH+0Pzw+rV2PRjD9gpyFvX/JMzx3UaJNscPEdne9wtuolk6VJpS
KPTKTaXinS0grYvSUeY8+qmli20btNiaJ2La+giYAuPMiL99iStmlj+pTgnuVY65
JQIDAQAB
-----END PUBLIC KEY-----
    </Property>
  </Properties>
  <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
  <ResourceURL>java://edge-custom-httpsig-20200320.jar</ResourceURL>
</JavaCallout>

And the signature verifies.

I've enclosed a working API Proxy here. Can you try it?

apiproxy-denis-http-sig.zip

I've updated the Java callout to version 20200320, but I didn't actually change anything in the behavior. I re-factored the code a little and cleaned things up. I introduced a test for THIS particular case. It's a new JAR, but the old JAR should also work fine.

Looking again at YOUR Java verifier policy.

<JavaCallout name="Java-VerifyHttpSignature1">
    <Properties>
        <Property name="algorithm">rsa-sha256</Property>
        <Property name="public-key">{pkey}</Property>
    </Properties>
    <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
    <ResourceURL>java://edge-custom-httpsig-1.0.2.jar</ResourceURL>
</JavaCallout>

...I notice that you don't specify the 'headers' property. If you specify nothing , hmmmm.... I had not documented this edge case previously, but the designed behavior is that policy verifies just the date header. I have now updated the README with that information.

It would be insecure to just the inbound signature to specify the headers that must be signed; the set of headers must be explicitly enforced in some way on the receiving (verifying) side.

Hi Dino

Thank you very much

I can confirm that your proxy indeed works.

My old proxy with same configuration - not.

Once I reused (refreshed) your new jar - all worked on my old proxy.

Dino, can you please share the soruce code for new jar you posted?

OK, I've tested some more cases \ headers, so far so good. Now testing more deeply, I will update it here,

Thank you very much for quick help!

I've updated the repo at

https://github.com/apigee/iloveapis2015-hmac-httpsignature

...with the modified source code.

Hi Dino
I've done more tests an QA on the development.

If you want me to open different thread - please tell me.

All working well, till' we have only 1 header signed, e.g. "user=denis" or other "key=value" occurrence, like "kuki=spooki" etc.

Once I'm trying to sign more then 1 header, my verification goes bananas:

My signing string:

digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
psu-id: 1337

My Java code:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<JavaCallout name="Java-VerifyHttpSignature-RSA1">
    <Properties>
        <Property name="algorithm">rsa-sha256</Property>
        <Property name="headers">digest x-request-id tpp-redirect-uri psu-id</Property>
        <Property name="public-key">
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9htfJRKA3EEbvmvrqKON
CGSDHYH3bJffNeca1sqvSN8uA2r16qabG5n21kvOZuzYr6gsK1Qpi870vELbir00
xybyXTJKDjXsSTO+hSVa+bmr8V+ncAJr8ZkyWjPDYufGAsXqbLbUVWAbtiyCbgdA
YBktWwXthQdz867l1ow21ZgR+vwzSDAAg8rK6PGIxqZ+7iVIUMW9eGJpr5vSdRXX
Oushgcr84EBs7TH+0Pzw+rV2PRjD9gpyFvX/JMzx3UaJNscPEdne9wtuolk6VJpS
KPTKTaXinS0grYvSUeY8+qmli20btNiaJ2La+giYAuPMiL99iStmlj+pTgnuVY65
JQIDAQAB
-----END PUBLIC KEY-----
    </Property>
    </Properties>
    <ClassName>com.google.apigee.callout.httpsignature.SignatureVerifierCallout</ClassName>
    <ResourceURL>java://edge-custom-httpsig-1.0.2.jar</ResourceURL>
</JavaCallout>

*** please notice that I've replaced the old jar (1.0.2.jar) with your new one, so don't pay attention to the jar reference name, it is yours

My HTTP request:

GET /httpsig2/rsa-t1 HTTP/1.1
Host: xx-xx-xx-xx:9001
Signature: keyId="SN=example",algorithm="rsa-sha256", headers="digest x-request-id tpp-redirect-uri psu-id", signature="O46rA6GatQwE9PuOvjOkwaBqzafqS+W4ngIQd20UJ0M4g9W+NsH+37BiX3hiV45dfI0lNfvFLY5+DTp8rVurSvEIsg2Wj6Uydawi6G5sj7fsuC2jb0dNShdGCmY0X6LLoEYgBXxorqdO0mnLkxgbWLJHkDPj6BDt4Xv/ivt3+AAQUQ4PazNGcCSBAbAbA50433TESgZWA6mJu9/4oSXbZdNxWzeqxvlYyTFjJWlY2NPhL2UAdo+q8+Rb91yUtjjqNznFgEqHbQjLiGs8pPin5jHswfXSbI798LieV5gs7zJtoKdrBGU9Qd10Y5BYK4EWG2QqW61PTaeYu8mzkO9p9g=="
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
psu-id: 1337

...and signature validation always false:

{
  "app.name": "",
  "apiproduct.name": "",
  "signature": {
    "keyId": "SN=example",
    "algorithm": "rsa-sha256",
    "headers": "digest x-request-id tpp-redirect-uri psu-id"
  },
  "verification": {
    "isValid": "false",
    "requiredAlgorithm": "rsa-sha256",
    "requiredHeaders": "digest x-request-id tpp-redirect-uri psu-id",
    "timeskew": "0",
    "signingBase": "digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=|x-request-id: 00000000-0000-0000-0000-000000000004|tpp-redirect-uri: https://www.sometpp.com/redirect/|psu-id: 1337",
    "computedSignature": "",
    "error": ""
  }
}

if I will sign a single header, e.g. "digest" - all works.

Maybe the problem with 'new line break' while signing? btw, on the online signing service signature validate successfully. I think it is connected with 'order' of headers signed, e.g. signing string have to be validated in same order as signed:

x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337

...are not the same signature string as:

digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337
x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/

So while the code receiving incoming headers, what order they are compared? I think they need to be in the same order as defined in the:

<Property name="headers">digest x-request-id tpp-redirect-uri psu-id</Property>

Can you please take a look again and help? What am I missing?

Thanks,

-D

@Dino-at-Google, hey Dino, can you help me out with this? If you want me to open new topic, please update, I'll do so.

Let me look.

---

Hi Denis

The order in which the headers are concatenated to make the signing base is the order in which the headers are mentioned in the headers= in the Signature header.

From v12 of the spec:

2.1.6.  headers

   OPTIONAL.  The `headers` parameter is used to specify the list of
   HTTP headers included when generating the signature for the message.
   If specified, it SHOULD be a lowercased, quoted list of HTTP header
   fields, separated by a single space character.  If not specified,
   implementations MUST operate as if the field were specified with a
   single value, `(created)`, in the list of HTTP headers.  Note:

   1.  The list order is important, and MUST be specified in the order
       the HTTP header field-value pairs are concatenated together
       during Signature String Construction (Section 2.3) used during
       signing and verifying.


So if your request includes this:

Signature: keyId="SN=example",algorithm="rsa-sha256", headers="digest x-request-id tpp-redirect-uri psu-id", ...

Then your client must have constructed the signing string like this:

digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337
x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
psu-id: 1337

(And the order of the "required" headers in the policy configuration does not matter)

Conversely, If your client signs in this order:

x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337

...then your signature header must be like this:

Signature: keyId="SN=example",algorithm="rsa-sha256", headers="x-request-id tpp-redirect-uri digest psu-id", ...

ps: I have found a bug in the nodejs httpSigClient.js - it does not process header values correctly if there is a colon in the value. I'm fixing that.

Hi Dino,

I really appreciate your effort and time for me, so thank you very much!

I can't make it work on this specific case we are working on:

My request to proxy:

GET /denis-http-sig/t1 HTTP/1.1
Host: xxxxxxxxxx:9001
Signature: keyId="test", algorithm="rsa-sha256", headers="x-request-id tpp-redirect-uri digest psu-id", signature="1f8LbjHNDJc0/eUT7q9IKyCnrA8ocXI5GFr9jjdCjWAF3hR6UiYiq+1BS0/2RWjBig9BjpRkRKwB/UU8bUquIp0dYKVSGPFwn/ZvultbA+aHpu827oVt588kuKeNxiANk6DfVcToqV+OeSRPLh5htQyBKCM3DAUEWFtcL/QUmc1YHLRiBpKc/IYOiTygh2NCMt+x4Q6Qm649FjZpVr3n/vk/Po6Y1tJN3ocxtTdP82gxKsjtg4/fhge11sXWDN1j8nIIb/NE9F60V7B/Fo/5vHi9HyKAcI6e2HRp0yq6WTMxB9+kIWH0fosvQRZw+M83V+wu62b0ocnrx3ihWCfYnQ=="
x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337

My signature(clear):

x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337

My signature(signed):

1f8LbjHNDJc0/eUT7q9IKyCnrA8ocXI5GFr9jjdCjWAF3hR6UiYiq+1BS0/2RWjBig9BjpRkRKwB/UU8bUquIp0dYKVSGPFwn/ZvultbA+aHpu827oVt588kuKeNxiANk6DfVcToqV+OeSRPLh5htQyBKCM3DAUEWFtcL/QUmc1YHLRiBpKc/IYOiTygh2NCMt+x4Q6Qm649FjZpVr3n/vk/Po6Y1tJN3ocxtTdP82gxKsjtg4/fhge11sXWDN1j8nIIb/NE9F60V7B/Fo/5vHi9HyKAcI6e2HRp0yq6WTMxB9+kIWH0fosvQRZw+M83V+wu62b0ocnrx3ihWCfYnQ==

I'm using private key in the first message of this topic, and public key respectivly;

And signature validation always fails:

{
  "signature": {
    "keyId": "",
    "algorithm": "",
    "headers": ""
  },
  "verification": {
    "isValid": "false",
    "requiredAlgorithm": "rsa-sha256",
    "requiredHeaders": "x-request-id tpp-redirect-uri digest psu-id",
    "timeskew": "0",
    "signingBase": "x-request-id: 00000000-0000-0000-0000-000000000004|tpp-redirect-uri: https://www.sometpp.com/redirect/|digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=|psu-id: 1337",
    "computedSignature": "",
    "error": ""
  }
}

Verification passes on every online signature verification, but not in my Java callout 😕

Dino, it is strange, but with your signature (provided in github with nodejs - all valid), I'm guessing my singing online service is the problem.

This one works:

keyId="SN=dkjdk",algorithm="rsa-sha256",headers="x-request-id tpp-redirect-uri digest psu-id",signature="xHdJElmOwyg3PISD8he918hvB8osE9vKjFPl73dY0Mv15OrxlASTjzGiOAMcxSex6a+KG0nn5bua6uy3fdTtUPY2JeAuA88/MLpEzjlBxOBwxka7qcVGlaoG7FqrSYJRDYxNf0X1BlKygCzJyymH9D4cplwYtXx+BH5WeLdpko6Fyu0FadknPUUta/AYcEC5K7qAmNY1HQjAnXzDjQWCplB7uacE0NL0fqNdf/5OQc8xdWOml77ov8EeBV3iWI8lbN6j5jiIJaTVtni9Nd3Auu9wTbPVKQvusm+jMVpPBhpQ3WJIfsxpqmNVavWWOWh/wR2AQv3tskylUNxRfHaFRA=="

My signature I signed online with same data & private key have different signature:

keyId="test", algorithm="rsa-sha256", headers="x-request-id tpp-redirect-uri digest psu-id", signature="1f8LbjHNDJc0/eUT7q9IKyCnrA8ocXI5GFr9jjdCjWAF3hR6UiYiq+1BS0/2RWjBig9BjpRkRKwB/UU8bUquIp0dYKVSGPFwn/ZvultbA+aHpu827oVt588kuKeNxiANk6DfVcToqV+OeSRPLh5htQyBKCM3DAUEWFtcL/QUmc1YHLRiBpKc/IYOiTygh2NCMt+x4Q6Qm649FjZpVr3n/vk/Po6Y1tJN3ocxtTdP82gxKsjtg4/fhge11sXWDN1j8nIIb/NE9F60V7B/Fo/5vHi9HyKAcI6e2HRp0yq6WTMxB9+kIWH0fosvQRZw+M83V+wu62b0ocnrx3ihWCfYnQ=="

This is super odd 🙂

Dino, sorry for bringing the topic, I just wanted to update you that I found the reason why signatures didn't match. I actually started to develop QSEAL utility based on crypto.js for Israel Open Banking community, and I found in my development fun fact:

user: denis\r\npermission: admin

is no the same as

user: denis\n\permission: admin

therefore signatures not matched (I assume source where I signed uses \r\n, I just compared with my development, usage of \r\n brings same results), but your java works with \n only, and this is according to RFC:

If value is not the last value then append an ASCII newline `\n`. The string MUST NOT include a trailing ASCII newline.

amaizing how single char can change so much 🙂

yes! Correct! It's very tricky.

I tried to describe that in a prior response (here).

Using a webtool, it's never clear whether the web tool is including \r\n or just \n for the newlines. The way I found the source of the discrepancy you observed, which I described in that prior response... was by using Chrome dev tools and looking at the payloads sent over the wire.

I'm glad you are sorting it out!

I'm not getting that output value for a signature, for the inputs you are showing.

What tool are you using to compute these signatures?

this one for signing and validation

I guess once signed in html window \n line managed differently as from CLI

I will look at the online tool.

Have you tried the httpSigClient.js thing that is included in this repo?:

https://github.com/apigee/iloveapis2015-hmac-httpsignature

ahh. yes... the online tool is not handling newlines as the http-signature specification requires. Using the Chrome debugger I Was able to see that the online is serializing your "string to sign", which is this:

x-request-id: 00000000-0000-0000-0000-000000000004
tpp-redirect-uri: https://www.sometpp.com/redirect/
digest: SHA-256=TGGHcPGLechhcNo4gndoKUvCBhWaQOPgtoVDIpxc6J4=
psu-id: 1337<br>

...with a \r\n sequence between each line. The http-signature specification requires that the lines be concatenated with \n . If I hack the signer.js module used by the httpSigClient.js tool, to concat with \r\n, I get the same signature that the online tool generates.

So that online tool is soooo close... but it is not quite doing what you want for Http-Signature.

I don't know of an online tool that generates or verifies http-signature.

For your data, the actual signature should be:

Signature: keyId="SN=dkjdk",algorithm="rsa-sha256",headers="x-request-id tpp-redirect-uri digest psu-id",signature="xHdJElmOwyg3PISD8he918hvB8osE9vKjFPl73dY0Mv15OrxlASTjzGiOAMcxSex6a+KG0nn5bua6uy3fdTtUPY2JeAuA88/MLpEzjlBxOBwxka7qcVGlaoG7FqrSYJRDYxNf0X1BlKygCzJyymH9D4cplwYtXx+BH5WeLdpko6Fyu0FadknPUUta/AYcEC5K7qAmNY1HQjAnXzDjQWCplB7uacE0NL0fqNdf/5OQc8xdWOml77ov8EeBV3iWI8lbN6j5jiIJaTVtni9Nd3Auu9wTbPVKQvusm+jMVpPBhpQ3WJIfsxpqmNVavWWOWh/wR2AQv3tskylUNxRfHaFRA=="

I will Dino

I also checked now online references and examples of signatures on numerous developer portals(open banking) - and with usage of their example signatures and public keys (or certificates) - gives me true result in your validator, so I'm pretty sure I was chasing the tail and this signing service gives incorrect signatures 🙂

You can try this one?

https://dinochiesa.github.io/httpsig/

It's basic, but it works for simple cases.

Hi Dino

I did all possible QA cases, with your node.js (I compiled standalone client for my self) - and can confirm that it works with any RSA key (1024-4096) + all validation working with multiple headers.

https://dinochiesa.github.io/httpsig/ giving me isValid:false (even if you hit F5, generate a signature and validate it immediately) -> not working, no matter what I try to sign.

For me, node.js is superb tool and provides the goods for self-checking

Thank you very much for your effort and time! Much appreciated, and it was fun 🙂

Denis