A proxy "joining" multiple HTTP requests into one

@sea-snake You misunderstand the purpose of my algorithm:

I use vetKeys not only to verify that the request is coming from a trusted canister, but also to verify (with the purpose to punish a misbehaved canister hardware provider) that the canister does not do extraneous (I mean, additional, not requested by the client) requests to the proxy. I highly doubt that this can be done without vetKeys, because a misbehaving canister hardware can steal the secret key and do additional requests, as I explain in the next paragraph.

It is important to note that, if we don’t use vetKeys for the Canister-Key: signature, then the keeper canister hardware could forge the signature for more “long time”/“short time” nonce pairs and send fake requests (possibly, for example, stealing OpenAI tokens). You propose to use tECDSA instead. I have no idea who would keep several keys of tECDSA. Do you propose to create several canisters to do it?

Well, I seem to be right in the above by “feeling the math”, but cryptography is a complex topic, so I can’t exclude the possibility of my error. If I have some mistake, point it to me.

A tECDSA or canister signature can’t be forged by a single node since it relies on threshold signing (multiple nodes).

Again: Do you propose me to create multiple canisters? How many? Isn’t the cost of creating multiple canisters too high?

Canister signature can’t be forged, but it can be reused multiple times by a single canister. My algorithm is meant to protect from reusing a single key multiple times. Can it be done without vetKeys? I think, no, but you can try to change my mind.

Oh, sorry, it was me who misunderstood, not you. Accordingly my understanding, both vetKeys and canister signature are tECDSA and do the same thing, except that canister signature does not bring a new additional key into the system. So, I’ve rewritten my algorithm (see “workflow” above) to use tECDSA instead of vetKeys. Now a few leading items are removed from the algorithm, simplifying it.

I confess that I had a misunderstanding: That a request comes from a trusted canister can be validated by simply checking a canister-generated token with canister’s ECDSA. @zensh was right. Moreover, this no more requires punishing a canister post-factum, because it simply cannot receive a status 200 reply from the proxy, if misbehaves. I tried to use vetTokens by the scheme “I have a hammer, therefore everything is a nail.”

However, the @sea-snake’s idea and @zensh waiting for vetKeys to use vetKeys to cipher requests still seems wrong for me: Inside the IC the sent concept can be intercepted anyway (unless it is cryptographically obfuscated) and outside IC we are protected by HTTPS anyway, no need to introduce an additional level of encryption using vetKeys. Or do I again have a misunderstanding?

I propose to modify vetKeys API to allow such a use case of vetKeys. Well, for our particular task, tECDSA is enough and vetKeys are not required.

However, see my question, I am not yet 100% sure that signing by tECDSA is not vulnerable of multiple signatures attack, let first get an authoritative answer to that question.

Sorry for addressing this issue second time. Disclaimer: I am @zensh’s competitor. But I will address it again, because here the context of @zensh’s words need a response.

Storing private key in canister is unsafe against hacked canister hardware. (My current code also does this, too, but I am in process of rewriting.) Canister platform can steal the private key and do unsanctioned calls (e.g. to steal OpenAI tokens).

The safe implementation is to use the ICP’s variant of tECDSA.

VetKD signing isn’t in th spec because that’s basically what tECDSA is already available and meant for, vetkd is solely focused on en/decryption.

Another alternative for signing besides tECDSA is canister signatures, this basically is the certified data functionality that the asset canister uses to verify query responses and II uses to create signed delegations. As far as I remember, tECDSA is more expensive than the latter (cycles) but these sort of details are something I would recommend investigation, measuring and weighing the options.

So, to be sure that I understand:

If vetKD signing were be available, it would confirm that the canister that has access to vetKey signed, but it is exactly the same, as a definitely pointed canister signing, that is would be just a more complex API for canister signing.

Concerning encryption/decryption, why not make SK key hidden from the canister in the same way as in canister signing SK key is not exposed? Won’t it make signing more secure (against the “key replay” attack that I discovered, but applied to encrypting rather than to signing)?

Also, I’ve recently read in the Internet that ECDSA is not suited for encryption/decryption, because its properties as an encryption key are not yet enough researched, and it is therefore suited only for signing. What’s about this?

Saw the updated message above, instead I would hash the whole http request (url, headers, body bytes) then sign this hash. The proxy then can then hash the request and check if this matches the signature. Additionally a nonce could be added to the request to prevent replay attacks. The proxy then has a “window” of x minutes that it will ignore requests with the same hash.

This is basically similar to how canister calls are signed and sent in agent-js to the IC api boundary node. On the IC the window is 5 minutes if I remember correctly.

Signing the entire request in IC would unnecessarily eat too many cycles. It is enough to sign the principal of the canister (in the case if the code in the canister behaves correctly, what is assumed).

Nonce is a correct idea that I mentioned above.

If you sign the principal of the canister, then you can’t trust the request sent along that signature, since anyone can attach that signature to a different request. Also to a sign a request, signing the (way shorter) hash of the request would suffice.

Signing a principal and providing a nonce is enough. As a nonce we can take stable Nat incremented by one variable, to warrant that nonce does not repeat. Then, provided that the canister will follow my spec, it is easy to check at the side of the proxy that nonces always increase and therefore a request can’t be replayed. The rest is verified by a canister signature of the principal.

I realized that I did the following error: Contrary to what I said, tECDSA signed stuff needs to contain the hash of the entire message, to avoid a malevolent replica to substitute another body.

But the above is no more important, because I am removing tECDSA support (it was estimated as a few USD cents).

A much less expensive way is, if the proxy sends an update call back to the canister that requested a HTTPS outcall with the hash of the outcall before delivering the request further. This request can be used by our canister to determine if it asked for this outcall or no.

Yesterday I released a beta of Join Proxy.

Security in the beta is not perfect: A malignant node can drain cycles from the user’s canister. But that is considered a low security risk. So the beta is practically usable for serious work (at least, declared so).

There remains a list of ToDo items.

3 Likes

Will we ever get such proxy hosted on-chain, so that we won’t have to deploy our own off-chain?
Without such proxy https outcalls are pretty limited