View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0008703 | GNUnet | reclaim | public | 2024-04-04 02:59 | 2024-06-08 12:03 |
Reporter | thejackimonster | Assigned To | schanzen | ||
Priority | normal | Severity | major | Reproducibility | always |
Status | closed | Resolution | fixed | ||
Product Version | Git master | ||||
Target Version | 0.21.2 | Fixed in Version | 0.21.2 | ||
Summary | 0008703: Consuming a ticket does not rely on the subjects key | ||||
Description | When you issue a ticket, it shouldn't be possible by any party besides the relying subject to consume the ticket gaining access to its linked attributes. However it seems like if you issue a ticket on a host, every key is able to consume the ticket successfully. | ||||
Steps To Reproduce | gnunet-identity -C a gnunet-identity -C b gnunet-identity -C c key_a=$(gnunet-identity -d -e a | awk '{print $3}') key_b=$(gnunet-identity -d -e b | awk '{print $3}') key_c=$(gnunet-identity -d -e c | awk '{print $3}') gnunet-reclaim -e a -a aaa -V bbb ticket=$(gnunet-reclaim -e a -i aaa -r $key_b) gnunet-reclaim -e a -C $ticket gnunet-reclaim -e b -C $ticket gnunet-reclaim -e c -C $ticket | ||||
Additional Information | I've tried whether a ticket can also be consumed by any party on a different host. So I copied ego keys and namestore to a separate machine. But no key was able to consume the ticket instead, not even the one from original issuer or relying subject. | ||||
Tags | No tags attached. | ||||
|
Yes, I think we talked about this before. The Ticket is not itself protected from unauthorized access. Meaning that if you accidently publish or disclose it to third parties, they will be able to use it. In such a case, you have to revoke the ticket and issue a new one. |
|
But if that's intended, why does the function GNUNET_RECLAIM_ticket_consume() require a private identity key? |
|
I've implemented this patch now: https://git.gnunet.org/gnunet.git/commit/?h=dev/thejackimonster/reclaim-changes&id=087834e85fb20f98b6695f62cff2b5b65a32e542 With this the ticket can only be consumed by the relying subject. Looking at the paper, I also assumed such encryption and decryption via public and private key of that identity would be used internally. But maybe there's a reason for the current implementation, I don't see right now. So I keep the patch on a separate branch first. |
|
The reason why ticket_consume contains the private key is (probably) historical, but it made sense to keep it in oder to do some sanitiy checking (am I the RP). The "problem" is that with your patch you are now encrypting twice, and I think if it is added it should be properly justified. I initially thought you wanted to encrypt the ticket, which would make more sense (then you only have to encrypt one thing and not all attribute references). I may be swayed to say yes to a ticket that is encrypted to a RP by default. But it just is not obvious that this is what you want. Encryption will cause a lot of overhead if you do Encrypt-then-Sign. And if you already have a secure channel (e.g. TLS) with your RP, it is completely unnecessary. For example, reclaimID has an OIDC layer in which the user always has access to a secure channel (HTTPS) to the RP. If your use case does not have such a secure channel, then yes, you may want to encrypt the ticket (or rather: establish a secure channel first). |
|
To get on the right path I suggest the following: Formulate an attacker that would some abuse the fact that your proposed encryption is not in place. Then we can talk about mitigations. You example in the OP is incomplete: "However it seems like if you issue a ticket on a host, every key is able to consume the ticket successfully" <= how is the adversary on the same host (so another user I assume) gaining access to the ticket? |
|
Here is another idea: We could issue the ticket for a RP with key pair (a,B) by generating an ephemeral ECDH key pair (a,A) and publish the attribute references under label: = SHA(ECDH(a,B)) The transferred ticket then contains not the label (or rnd what I think it is called), but only A. Only the RP the ticket was issued for will be able to calculate label := SHA(ECDH(b,A )) to retrieve the attributes. Encryption is then still outsourced to GNS, but you have your RP binding. |
|
I think one issue I can think of is that the relying party might act malicious. So when A provides B a ticket to access some attributes from A. B can practically generate a pseudo-ticket for C which looks like it was created from A for C to access the same attributes. Currently this would be done via swapping out the public key from B with the one from C in a ticket (from A to B). It looks like a ticket from A. It behaves like a ticket from A. But I think B should not be able to fake such tickets. It invalidates the signature from A to some degree. You can only verify that the attributes are set by A but you don't know whether A actually provided you access to them rather than anyone. Even if we encrypt the label from the ticket, this issue stays, I think. But it's solved if the attribute references are encrypted so that only B can read them. Because B can't publish similar references which can be decrypted by C in the zone from A. |
|
If C is also malicous, then B can just forward the decrypted attribute references (or the attribute values) to C on demand. If C is not malicous, and the attack is B impersonating A through a ticket, then this should always be mitigated by having the ticket origin authenticated. E.g. Pubkey authentication / establishment of a secure channel between A and B/C. Using the DH approach above would also prevent the ticket abuse. But so would a simple signature from A on the ticket. So I think we may want to add the signature of the issuer to the ticket. And we may want to replace the random secret in the ticket with an ephemeral DH key. Still, I would not encrypt the attribute references. Under the DH and EUF assumptions of the primitives above, the GNS encryption itself should be sufficient. |
|
Okay, sounds reasonable. |
|
After some more discussions I think this can be (while we are at it) improved more: 1. The ticket does not really need the AUDIENCE pubkey. Once the RP resolves the shared secret label in the IDENTITY zone, it should be able to resolve a record of type RECLAIM_RP_KEY that contains its pubkey. If it does not, it is not a ticket issued that was issued by IDENTITY for AUDIENCE. This removes the need for a signature on the ticket. In fact, it would allow us to define a ticket as a GNS name with format <TicketID>.<IDENTITY> which is quite nice. 2. The ticket ID (the secret label used to resolve the attribute references) may be derived from a DH as noted above. But I am not sure if that is always necessary. It imposes a (slight) burden on implementations that could otherwise solely rely on GNS. I need to think about this a bit. I will update https://lsd.gnunet.org/lsd0002/ with input from this discussion. |
|
I have made some changes to the reclaim API in master: 1. The ticket is now simply a GNS name in the form <secret label>.<zTLD> where <zTLD> is the issuer public key Base32GNS encoded. 2. The audience is no longer part of the ticket. 3. When issuing a ticket, the issuer must provide a Relying Party URI (RP URI). This is a string. It is usually provided by the RP. For example: urn:gns:<Base32(identity)> 4. When provided with a Ticket, the RP resolves the contained GNS name and MUST verify that the RP URI matches what it expects to be. The RP URI is found in a URI record. The ticket_consume API requires the caller to provide the expected RP URI and takes care of this check. In your attack, B can no longer forge a ticket by replacing the audience key as it no longer exists. Also, the RP can now verify that the ticket was actually issued to it by providing a suitable RP URI. So the attack is thwarted. Transfer of the ticket must still be done securely. But this is "out of band" of the reclaimID authorization flow. Note that if you need to extract the RP identity for some reason when handling the ticket, you need to provide a RP URI that will allow you to extract this info again. The ticket_consume API will NOT give you the retrieved RP URI as you have to provide it anyway. I have tried to modify the messenger API to accomodate for the changes, but I guess both messenger and the OpenID plugins are currently not properly functioning with the new API. |
|
Sounds like a good solution. Since the issuer and the relying party both may know the RP URI, they can both consume the ticket, I assume. So that means I probably don't need to adjust libgnunetchat because of these changes. Otherwise I think I will need to adjust the ticket message struct from the Messenger service. So that it either carries the ticket as well as the RP URI or it's possible to derive the RP URI from the public key of the RP. So both (recipient and sender) can consume the ticket. I also like that the ticket is now only a GNS name. That means I can probably use a variable char array in the ticket message body. That allows dropping the include of the reclaim header in the messenger service header. Since all core functionality regarding tickets for attribute exchange in the chats is in libgnunetchat anyway. |
|
Resolving and scheduling for next release. |
|
0.21.2 released |
Date Modified | Username | Field | Change |
---|---|---|---|
2024-04-04 02:59 | thejackimonster | New Issue | |
2024-04-04 08:33 | schanzen | Note Added: 0022101 | |
2024-04-04 12:11 | thejackimonster | Note Added: 0022106 | |
2024-04-04 23:19 | thejackimonster | Note Added: 0022119 | |
2024-04-05 19:31 | schanzen | Note Added: 0022125 | |
2024-04-05 19:51 | schanzen | Note Added: 0022128 | |
2024-04-06 11:21 | schanzen | Note Added: 0022134 | |
2024-04-07 20:56 | thejackimonster | Note Added: 0022139 | |
2024-04-08 10:20 | schanzen | Note Added: 0022142 | |
2024-04-08 10:48 | schanzen | Note Edited: 0022142 | |
2024-04-08 12:23 | thejackimonster | Note Added: 0022143 | |
2024-04-08 14:57 | schanzen | Note Added: 0022149 | |
2024-04-30 11:35 | schanzen | Note Added: 0022320 | |
2024-04-30 11:35 | schanzen | Assigned To | => schanzen |
2024-04-30 11:35 | schanzen | Status | new => assigned |
2024-04-30 11:35 | schanzen | Note Edited: 0022320 | |
2024-04-30 11:37 | schanzen | Note Edited: 0022320 | |
2024-04-30 11:38 | schanzen | Note Edited: 0022320 | |
2024-05-02 22:52 | thejackimonster | Note Added: 0022330 | |
2024-05-03 19:10 | schanzen | Status | assigned => resolved |
2024-05-03 19:10 | schanzen | Resolution | open => fixed |
2024-05-03 19:10 | schanzen | Fixed in Version | => 0.21.2 |
2024-05-03 19:10 | schanzen | Note Added: 0022339 | |
2024-05-03 19:10 | schanzen | Target Version | => 0.21.2 |
2024-06-08 12:03 | schanzen | Note Added: 0022559 | |
2024-06-08 12:03 | schanzen | Status | resolved => closed |