Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new keyshare protocol (keyshare server parts) #240

Merged
merged 45 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
8c3ba8a
Add first draft of keyshare protocol sequence diagram. Incomplete and…
Sep 1, 2022
a52ed18
Mark new changes in keyshare protocol green in sequence diagram.
Nov 14, 2022
52a52f3
Adjust /getPs endpoint name in sequence diagram to match implementation.
Nov 15, 2022
9260d48
Introduce /getPs endpoint for initially fetching keyshare server P (R…
Nov 15, 2022
9fd5e0f
Fix linter issue (typo) in sequence diagram.
Nov 15, 2022
d00d3fe
Add GeneratePs functionality test.
Nov 16, 2022
72ebce6
Add comment to verifyAccess calls.
Nov 28, 2022
8e2a1ad
Merge pull request #267 from privacybydesign/getP-endpoint
bobhageman Nov 28, 2022
b7a4878
Merge branch 'master' into new-keyshare-protocol
Dec 2, 2022
cf3f06c
Add /api/v2 route and move getP there.
Dec 2, 2022
8f365cd
Upgrade to latest gabi version which contains the crypto for the prov…
Dec 2, 2022
b22ef68
Cleanup go.sum.
Dec 2, 2022
5f4c483
Introduce /api/v2/getCommitments endpoint.
Dec 2, 2022
f069df4
Remove /api/v2/getPs tests from v1 server tests.
Dec 2, 2022
d3317f9
Pass nil instead of random placeholder for keyshareP to new credentia…
Dec 9, 2022
85aace0
feat: support gabi with updated keyshare protocol
sietseringers Dec 11, 2022
23213cd
Update gabi dependency to include complete legacy keyshare protocol.
Dec 12, 2022
b5e4ad8
Print PublicKeyIdentifier correctly in error text.
Dec 12, 2022
f06a57a
Fix linter warnings.
Dec 12, 2022
a919ad7
Merge pull request #274 from privacybydesign/getCommitments-working
synaptic-cleft Dec 12, 2022
fb779f2
Correct nesting of /api/v2 router.
Dec 12, 2022
eecf58a
Fix typo in JSON marshalling of ProofPCommitmentMapV2.
Dec 20, 2022
e722c14
Adjust error messages to lower-case for consistency with Go best prac…
Dec 20, 2022
f9ae2f8
fix: add missing return statement in error handling
sietseringers Dec 21, 2022
8ce3c5b
Merge pull request #273 from privacybydesign/getCommitments
ivard Jan 9, 2023
6c8536d
Merge pull request #275 from privacybydesign/master-merge-only
ivard Jan 9, 2023
88466bd
Add keyshare server getResponse v2 endpoints (both linkable and unlin…
Jan 19, 2023
24e164f
Refactor: rename parameter in keysharecore's GenerateResponseV2
ivard Jul 28, 2023
e573ad0
Docs: add explanation about keysharecore's GenerateResponseV2 linkab…
ivard Jul 28, 2023
77ec747
Merge pull request #278 from privacybydesign/get-response
ivard Jul 28, 2023
dcd2b2e
Merge branch 'master' into new-keyshare-protocol
ivard Aug 1, 2023
f785375
Fix keyshare server sessions involving a legacy issuer
sietseringers Aug 28, 2023
6778fad
Merge pull request #333 from privacybydesign/new-keyshare-protocol-le…
ivard Aug 28, 2023
3aadc2d
Chore: remove leftover TODOs
ivard Sep 1, 2023
926dd06
Chore: updated changelog
ivard Sep 1, 2023
a26449a
Chore: fix duplicate headers in changelog
ivard Sep 1, 2023
1171a70
Chore: make PMap JSON tags consistent with variable names
ivard Sep 4, 2023
c3361f3
Merge pull request #337 from privacybydesign/new-keyshare-protocol-re…
ivard Sep 4, 2023
a57b75d
Merge branch 'new-keyshare-protocol' into new-keyshare-protocol-ps
ivard Sep 4, 2023
1888bb8
Merge pull request #338 from privacybydesign/new-keyshare-protocol-ps
ivard Sep 4, 2023
f151be3
Merge branch 'master' into new-keyshare-protocol
ivard Sep 4, 2023
1349854
Merge branch 'master' into new-keyshare-protocol
ivard Sep 5, 2023
19e5fac
Merge branch 'master' into new-keyshare-protocol
ivard Sep 5, 2023
5862914
Docs: remove duplicate changelog line
ivard Sep 5, 2023
322f57e
Merge branch 'master' into new-keyshare-protocol
ivard Sep 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
}
```
- Renewal endpoint for keyshare attribute in the keyshare server (`/users/renewKeyshareAttribute`)
- Keyshare server /api/v2/prove/... endpoints for the new keyshare protocol

### Changed
- `KeyshareVerifyPin` function in irmaclient ensures the keyshare attribute is valid

### Changed
- Sending the account expiry email is done when user has only valid e-mail addresses
- Strip unnecessary details from database errors

Expand Down
79 changes: 79 additions & 0 deletions docs/keyshareFlow.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
@startuml
skinparam backgroundColor #transparent
participant "IRMA app" as app
participant "requestor" as requestor
participant "keyshare server" as keyshare
participant "database" as db
participant "mail server" as mail

title Keyshare server endpoints

app -> keyshare ++: POST /client/register <font color=#1D5B2A>signed</font> jwt:{pin, email, language, <font color=#1D5B2A>publickey</font>}
keyshare -> keyshare: validate jwt
keyshare -> db: Generate keyshare server account, \nincl secret <font color=#1D5B2A>and store publickey</font>
keyshare -> mail: Send registration mail \nif address is specified
keyshare -> keyshare: Issue keyshare credential
return Invisible issuing of keyshare credential \n(directly via session endpoints in keyshare server)
|||

'already enrolled app: similar to the one sent by the irmaclient when changing your IRMA PIN code
'note: hier komt een nieuwe jwt terug
app -> keyshare ++: <font color=#1D5B2A> POST /users/register_publickey signed jwt:{id, pin, publickey}
keyshare -> keyshare: <font color=#1D5B2A>validate jwt</font>
keyshare -> keyshare: <font color=#1D5B2A>validate PIN</font>
keyshare -> db: <font color=#1D5B2A>store publickey</font>
return <font color=#1D5B2A>jwt</font>
|||

'get challenge
app -> keyshare ++: <font color=#1D5B2A>POST /users/verify_start {id}
keyshare -> keyshare: <font color=#1D5B2A>generate challenge
return <font color=#1D5B2A>"pin_challengeresponse", challenge
|||

app -> keyshare ++: POST /users/verify/pin<font color=#1D5B2A>_challengeresponse</font> {id, pin, <font color=#1D5B2A>response</font>}
keyshare -> db: fetch user
keyshare -> keyshare: verify pin \n(incl reservePinCheck and blocking)
keyshare -> keyshare: <font color=#1D5B2A>verify response which correponds to challenge
return access token
|||

'reply attacks not possible, so no challenge-response needed
app -> keyshare ++: POST /users/change/pin <font color=#1D5B2A>signed jwt</font>:{id, oldpin, newpin}
keyshare -> db: fetch user
keyshare -> keyshare: reserve pin check
keyshare -> keyshare: <font color=#1D5B2A>validate jwt signature
keyshare -> db: check old pin and update with new pin
return OK
|||

app -> requestor: start session / get nonce
return nonce
|||

' initial P_t from kss, new endpoint, do once before issuance
app -> keyshare ++: <font color=#1D5B2A>POST /prove/getPs \n<font color=#1D5B2A>["irma-demo.IRMATube-1"] + access token
return <font color=#1D5B2A>P_t
|||

app -> app: <font color=#1D5B2A>hw=hash(P,W_uu)
|||

app -> keyshare ++: POST /prove/getCommitments \n["irma-demo.IRMATube-1"] + <font color=#1D5B2A>h_w</font> + access token
keyshare -> keyshare: verify token
keyshare -> keyshare: generate commitments
keyshare -> keyshare: <font color=#1D5B2A>store commitID for later requests</font>
return commitments W_t
|||

app -> app: generate c = hash(nonce,P,W), s_u
app -> keyshare ++: POST /prove/getResponse + \n<font color=#1D5B2A>nonce + s_u + W_u + P </font>+ access token
keyshare -> keyshare: <font color=#1D5B2A>verify h_w
keyshare -> keyshare: <font color=#1D5B2A>re-calculate c
keyshare -> keyshare: log for MyIRMA
keyshare -> keyshare: get commitment data from \nmemory store and build \nresponse with challenge
return <font color=#1D5B2A>+signed jwt over challenge which is in ProofP

app -> requestor: challenge/response, signed jwt, <font color=#1D5B2A>P=A*P_t || P=U*P_t

@enduml
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
github.com/hashicorp/go-retryablehttp v0.7.1
github.com/mdp/qrterminal v1.0.1
github.com/mitchellh/mapstructure v1.5.0
github.com/privacybydesign/gabi v0.0.0-20221012093643-8e978bfbb252
github.com/privacybydesign/gabi v0.0.0-20221212095008-68a086907750
github.com/sietseringers/go-sse v0.0.0-20200801161811-e2cf2c63ca50
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cast v1.5.0
Expand Down
14 changes: 3 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fxamacker/cbor v1.5.0/go.mod h1:UjdWSysJckWsChYy9I5zMbkGvK4xXDR+LmDb8kPGYgA=
github.com/fxamacker/cbor v1.5.1 h1:XjQWBgdmQyqimslUh5r4tUGmoqzHmBFQOImkWGi2awg=
github.com/fxamacker/cbor v1.5.1/go.mod h1:3aPGItF174ni7dDzd6JZ206H8cmr4GDNBGpPa971zsU=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
Expand All @@ -112,7 +111,6 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-co-op/gocron v1.28.3 h1:swTsge6u/1Ei51b9VLMz/YTzEzWpbsk5SiR7m5fklTI=
github.com/go-co-op/gocron v1.28.3/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
Expand Down Expand Up @@ -238,7 +236,6 @@ github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand Down Expand Up @@ -302,8 +299,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/privacybydesign/gabi v0.0.0-20221012093643-8e978bfbb252 h1:q5BP7Eh/x1GCyIToZTBYQXELmO876ezbQvek7gJaBg4=
github.com/privacybydesign/gabi v0.0.0-20221012093643-8e978bfbb252/go.mod h1:HQ6L5rKBY7qaqcheK6zpaVf7fhGWD0PvUAXJTDws+0M=
github.com/privacybydesign/gabi v0.0.0-20221212095008-68a086907750 h1:3RuYOQTlArQ6Uw2TgySusmZGluP+18WdQL56YSfkM3Q=
github.com/privacybydesign/gabi v0.0.0-20221212095008-68a086907750/go.mod h1:QZI8hX8Ff2GfZ7UJuxyWw3nAGgt2s5+U4hxY6rmwQvs=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
Expand All @@ -314,7 +311,6 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sietseringers/go-sse v0.0.0-20200801161811-e2cf2c63ca50 h1:vgWWQM2SnMoO9BiUZ2WFAYuYF6U0jNss9Vn/PZoi+tU=
github.com/sietseringers/go-sse v0.0.0-20200801161811-e2cf2c63ca50/go.mod h1:W/QHK9G0i5yrmHvej5+hhoFMXTSZIWHGQRcpbGgqV9s=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
Expand All @@ -333,14 +329,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
Expand All @@ -362,7 +356,6 @@ github.com/timshannon/bolthold v0.0.0-20210913165410-232392fc8a6a/go.mod h1:iSvu
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
github.com/x448/float16 v0.8.3/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand All @@ -387,7 +380,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
Expand All @@ -408,6 +400,7 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand Down Expand Up @@ -501,7 +494,6 @@ golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
100 changes: 97 additions & 3 deletions internal/keysharecore/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,35 @@ func (c *Core) verifyAccess(secrets UserSecrets, jwtToken string) (unencryptedUs
return s, nil
}

// GeneratePs generates a list of keyshare server P's, i.e. a list of R_0^keyshareSecret.
func (c *Core) GeneratePs(secrets UserSecrets, accessToken string, keyIDs []irma.PublicKeyIdentifier) ([]*big.Int, error) {
// Validate input request and build key list
var keyList []*gabikeys.PublicKey
for _, keyID := range keyIDs {
key, ok := c.trustedKeys[keyID]
if !ok {
return nil, ErrKeyNotFound
}
keyList = append(keyList, key)
}

// Use verifyAccess to get the decrypted secrets. The access has already been verified in the
// middleware. We use the call merely to fetch the unencryptedUserSecrets here.
s, err := c.verifyAccess(secrets, accessToken)
if err != nil {
return nil, err
}

var ps []*big.Int

for _, key := range keyList {
ps = append(ps,
new(big.Int).Exp(key.R[0], s.KeyshareSecret, key.N))
}

return ps, nil
}

// GenerateCommitments generates keyshare commitments using the specified Idemix public key(s).
func (c *Core) GenerateCommitments(secrets UserSecrets, accessToken string, keyIDs []irma.PublicKeyIdentifier) ([]*gabi.ProofPCommitment, uint64, error) {
// Validate input request and build key list
Expand All @@ -209,7 +238,8 @@ func (c *Core) GenerateCommitments(secrets UserSecrets, accessToken string, keyI
keyList = append(keyList, key)
}

// verify access and decrypt
// Use verifyAccess to get the decrypted secrets. The access has already been verified in the
// middleware. We use the call merely to fetch the unencryptedUserSecrets here.
s, err := c.verifyAccess(secrets, accessToken)
if err != nil {
return nil, 0, err
Expand Down Expand Up @@ -247,7 +277,52 @@ func (c *Core) GenerateResponse(secrets UserSecrets, accessToken string, commitI
return "", ErrKeyNotFound
}

// verify access and decrypt
// Use verifyAccess to get the decrypted secrets. The access has already been verified in the
// middleware. We use the call merely to fetch the unencryptedUserSecrets here.
s, err := c.verifyAccess(secrets, accessToken)
if err != nil {
return "", err
}

// Fetch commit
c.commitmentMutex.Lock()
commit, ok := c.commitmentData[commitID]
delete(c.commitmentData, commitID)
c.commitmentMutex.Unlock()
if !ok {
return "", ErrUnknownCommit
}

// Generate response
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"ProofP": gabi.KeyshareResponseLegacy(s.KeyshareSecret, commit, challenge, key),
"iat": time.Now().Unix(),
"sub": "ProofP",
"iss": c.jwtIssuer,
})
token.Header["kid"] = c.jwtPrivateKeyID
return token.SignedString(c.jwtPrivateKey)
}

// GenerateResponseV2 generates the response of a zero-knowledge proof of the keyshare secret, for a given previous commit and response request.
// In older versions of the IRMA protocol (2.8 or below), issuers need a response that is linkable to earlier issuance sessions. In this case,
// the ProofP.P will be set as well. The linkable parameter indicates whether the ProofP.P should be included.
func (c *Core) GenerateResponseV2(
secrets UserSecrets,
accessToken string,
commitID uint64,
hashedComms gabi.KeyshareCommitmentRequest,
req gabi.KeyshareResponseRequest[irma.PublicKeyIdentifier],
keyID irma.PublicKeyIdentifier,
linkable bool) (string, error) {
// Validate request
key, ok := c.trustedKeys[keyID]
if !ok {
return "", ErrKeyNotFound
}

// Use verifyAccess to get the decrypted secrets. The access has already been verified in the
// middleware. We use the call merely to fetch the unencryptedUserSecrets here.
s, err := c.verifyAccess(secrets, accessToken)
if err != nil {
return "", err
Expand All @@ -262,9 +337,28 @@ func (c *Core) GenerateResponse(secrets UserSecrets, accessToken string, commitI
return "", ErrUnknownCommit
}

proofP, err := gabi.KeyshareResponse(s.KeyshareSecret, commit, hashedComms, req, c.trustedKeys)
if err != nil {
return "", err
}

if uint(proofP.C.BitLen()) > gabikeys.DefaultSystemParameters[1024].Lh || proofP.C.Cmp(big.NewInt(0)) < 0 {
return "", ErrInvalidChallenge
}

// If the session involves a legacy issuer that doesn't understand the new keyshare protocol,
// return a legacy ProofP of the old keyshare protocol, differing as follows to a normal ProofP:
// - Includes P = R_0^userSecret in the Proof.P field (making the ProofP linkable)
// - The response in ProofP.SResponse should be just our response, not with the user's response added
// as done by added earlier in `gabi.KeyshareResponse()` above, so we subtract the user's response from it.
if linkable {
proofP.P = new(big.Int).Exp(key.R[0], s.KeyshareSecret, key.N)
proofP.SResponse.Sub(proofP.SResponse, req.UserResponse)
}

// Generate response
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"ProofP": gabi.KeyshareResponse(s.KeyshareSecret, commit, challenge, key),
"ProofP": proofP,
"iat": time.Now().Unix(),
"sub": "ProofP",
"iss": c.jwtIssuer,
Expand Down
12 changes: 12 additions & 0 deletions internal/keysharecore/operations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ func TestProofFunctionality(t *testing.T) {
jwtt, err := validateAuth(t, c, signer, secrets, pin)
require.NoError(t, err)

// For issuance, initially get P_t
_, err = c.GeneratePs(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("test"), Counter: 1}})
require.NoError(t, err)

// Get keyshare commitment
W, commitID, err := c.GenerateCommitments(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("test"), Counter: 1}})
require.NoError(t, err)
Expand Down Expand Up @@ -246,6 +250,10 @@ func TestCorruptedUserSecrets(t *testing.T) {
_, err = changePin(t, c, signer, secrets, pin, pin)
assert.Error(t, err, "ChangePin accepts corrupted keyshare user secrets")

// GeneratePs
_, err = c.GeneratePs(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("test"), Counter: 1}})
assert.Error(t, err, "GeneratePs accepts corrupted keyshare user secrets")

// GenerateCommitments
_, _, err = c.GenerateCommitments(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("test"), Counter: 1}})
assert.Error(t, err, "GenerateCommitments accepts corrupted keyshare user secrets")
Expand Down Expand Up @@ -313,6 +321,10 @@ func TestMissingKey(t *testing.T) {
jwtt, err := validateAuth(t, c, signer, secrets, pin)
require.NoError(t, err)

// GeneratePs
_, err = c.GeneratePs(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("DNE"), Counter: 1}})
assert.Error(t, err, "Missing key not detected by generatePs")

// GenerateCommitments
_, _, err = c.GenerateCommitments(secrets, jwtt, []irma.PublicKeyIdentifier{irma.PublicKeyIdentifier{Issuer: irma.NewIssuerIdentifier("DNE"), Counter: 1}})
assert.Error(t, err, "Missing key not detected by generateCommitments")
Expand Down
Loading
Loading