- Implements
x-cdoc2-auth-ticket
header parameter for GET /key-shares/${shareId}
Used by:
- cdoc2-java-ref-impl for auth-ticket creation
- cdoc2-shares-server for auth-ticket validation
CDOC2 has been tested with JDK 17 and Maven 3.8.8
mvn clean install
- Official documentation: (TODO) https://open-eid.github.io/CDOC2/2.0/03_system_architecture
/key-shares
OAS specification can be found here: https://github.com/open-eid/cdoc2-openapi
In short, cdoc2 key-shares auth ticket is used to authenticate against multiple key-share servers by signing authenticated data ones and not revealing auth data to other servers. For this SDJWT format is used.
SdJWT in encoded format:
<JWT_header>.<JWT_payload>.<JWT_signature>~<Disclosure1>~<Disclosure2>~
To decode sd-jwt use sdjwt.org
To generate auth-ticket client must first generate nonce
for each KeyShare
object accessed using
${serverBaseUrl}/key-shares/${shareId}/nonce endpoint.
JWT header for cdoc2 auth ticket:
{
"typ": "vnd.cdoc2.auth-token.v1+sd-jwt",
"alg": "RS256"
}
JWT payload:
{
"iss": "etsi/PNOEE-30303039914",
"aud": [
"https://css.ria.ee:443/key-shares/9EE90F2D-D946-4D54-9C3D-F4C68F7FFAE3?nonce=59b314d4815f21f73a0b9168cecbd5773cc694b6",
"https://ccs.another-organization.org:443/key-shares/5BAE4603-C33C-4425-B301-125F2ACF9B1E?nonce=9d23660840b427f405009d970d269770417bc769"
]
}
Nonce value was acquired from ${serverBaseUrl}/key-shares/${shareId}/nonce endpoint.
Before signing, "aud" will be replaced with a digest value as specified in sd-jwt specification:
{
"iss": "etsi/PNOEE-30303039914",
"_sd": [
"V5_DrlDm-FXeGPdcMZQrB7EZPEO98URIAYvykgWHZr0"
],
"_sd_alg": "sha-256"
}
Values of "aud" will be selectively disclosed to CSS server that has shareID accessed.
sd-jwt (auth ticket) for accessing key-share https://css.ria.ee:443/key-shares/9EE90F2D-D946-4D54-9C3D-F4C68F7FFAE3
with nonce
59b314d4815f21f73a0b9168cecbd5773cc694b6
(use sdjwt.org to decode)
eyJ0eXAiOiJ2bmQuY2RvYzIuYXV0aC10b2tlbi52MStzZC1qd3QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJldHNpL1BOT0VFLTMwMzAzMDM5OTE0IiwiX3NkIjpbIlY1X0RybERtLUZYZUdQZGNNWlFyQjdFWlBFTzk4VVJJQVl2eWtnV0hacjAiXSwiX3NkX2FsZyI6InNoYS0yNTYifQ.U31NbtFFn9CxdsQGuiQN0K_HPcJGdN1GEVepkAVGWk4Ug0cjWjZ79l6ghSqSD-tnlNJ3_yAcXJfihhmhCNFkPapupds-74U52RuwjN5iPJAI9BsvgXuXCXojQbF8pm2pwx9S7Cdxwoog22xMwwVl8_qU7f0k3XQjjQsC3Yqv5NA9iFCDnedkprwGozPEDf8VdU0O8zholhfDuMZcsjM540Cz795ab3s3MSscfG0E62ZqK1w6fi_Tbvh81KbFJtKM9JEZdwUGX69QrePBrqpb8Kmww5C-fjiFKRK7U02GbfccnBmaMAZ1KNTegez0ZEEBxk1m1cmSfcQ8vO6Cq539y3OJUVlytZ6ObD47Yx2PTuFGCtCVbPSx0q9VEVvPSgT3HuAHH1IIi7sakuznRzktUD8k_iJ86OJLJ6TN8_IZ9nzeTKbwlsqiY6g5B_ISdEiwhZqB_Rc8d3p7I70nQaYT9980jAEJvdKiRM2RvG4dYs7C4-hi7hXVrOgVvcFy0GpOb8pVy4N6Z6n1q9tQll90HRFo79CtY16u8Zc5AwUC9vifb7N7GO4ZQnhd4YIiX5FXYTMYXRY9MfMfswikCSrtXddBScQ-tOcacZ920fceMsrrrPHzKfOUd_G2GFwCFW2D2sPz5FOEWt5Cp6Xq1jPgITNvfJyFtEyeZlPjD8LDIfE~WyJFVjVmZjNrM1FQUlVaZ0ltaGRJUlhRIiwiYXVkIixbeyIuLi4iOiJsUkVVLURBY2FHTnpGVnkwVHVSSGM2TjZfRFBPSGxqQUxfWldpOVkzc0trIn0seyIuLi4iOiI2Q2lLSUpGZkYtSEhxQ1VuRm41dnY4T3RlLU5mbG5KWlYyS1VYMmk3VUNNIn1dXQ~WyJjak0yMGEwdUxROUdPaXExb3NMeXBBIiwiaHR0cHM6Ly9jc3MucmlhLmVlOjQ0My9rZXktc2hhcmVzLzlFRTkwRjJELUQ5NDYtNEQ1NC05QzNELUY0QzY4RjdGRkFFMz9ub25jZVx1MDAzZDU5YjMxNGQ0ODE1ZjIxZjczYTBiOTE2OGNlY2JkNTc3M2NjNjk0YjYiXQ~
sd-jwt above has 2 Disclosures (base64 encoded data between ~
)
WyJFVjVmZjNrM1FQUlVaZ0ltaGRJUlhRIiwiYXVkIixbeyIuLi4iOiJsUkVVLURBY2FHTnpGVnkwVHVSSGM2TjZfRFBPSGxqQUxfWldpOVkzc0trIn0seyIuLi4iOiI2Q2lLSUpGZkYtSEhxQ1VuRm41dnY4T3RlLU5mbG5KWlYyS1VYMmk3VUNNIn1dXQ
:
["EV5ff3k3QPRUZgImhdIRXQ","aud",[{"...":"lREU-DAcaGNzFVy0TuRHc6N6_DPOHljAL_ZWi9Y3sKk"},{"...":"6CiKIJFfF-HHqCUnFn5vv8Ote-NflnJZV2KUX2i7UCM"}]]
WyJjak0yMGEwdUxROUdPaXExb3NMeXBBIiwiaHR0cHM6Ly9jc3MucmlhLmVlOjQ0My9rZXktc2hhcmVzLzlFRTkwRjJELUQ5NDYtNEQ1NC05QzNELUY0QzY4RjdGRkFFMz9ub25jZVx1MDAzZDU5YjMxNGQ0ODE1ZjIxZjczYTBiOTE2OGNlY2JkNTc3M2NjNjk0YjYiXQ
:
["cjM20a0uLQ9GOiq1osLypA","https://css.ria.ee:443/key-shares/9EE90F2D-D946-4D54-9C3D-F4C68F7FFAE3?nonce\u003d59b314d4815f21f73a0b9168cecbd5773cc694b6"]
Note: Disclosure 1 also contains digest 6CiKIJFfF-HHqCUnFn5vv8Ote-NflnJZV2KUX2i7UCM
, but it is
not disclosed as ShareId belongs to another key-share-server.
Content of Disclosures:
Digest | Salt | Claim Name | Claim Value |
---|---|---|---|
V5_DrlDm-FXeGPdcMZQrB7EZPEO98URIAYvykgWHZr0 |
EV5ff3k3QPRUZgImhdIRXQ |
aud |
[{"...":"lREU-DAcaGNzFVy0TuRHc6N6_DPOHljAL_ZWi9Y3sKk"},{"...":"6CiKIJFfF-HHqCUnFn5vv8Ote-NflnJZV2KUX2i7UCM"}] |
lREU-DAcaGNzFVy0TuRHc6N6_DPOHljAL_ZWi9Y3sKk |
cjM20a0uLQ9GOiq1osLypA |
(no value) | https://css.ria.ee:443/key-shares/9EE90F2D-D946-4D54-9C3D-F4C68F7FFAE3?nonce\u003d59b314d4815f21f73a0b9168cecbd5773cc694b6 |
Note: Digest
can be calculated using
echo -n WyJFVjVmZjNrM1FQUlVaZ0ltaGRJUlhRIiwiYXVkIixbeyIuLi4iOiJsUkVVLURBY2FHTnpGVnkwVHVSSGM2TjZfRFBPSGxqQUxfWldpOVkzc0trIn0seyIuLi4iOiI2Q2lLSUpGZkYtSEhxQ1VuRm41dnY4T3RlLU5mbG5KWlYyS1VYMmk3VUNNIn1dXQ |openssl dgst -sha256 -binary|base64url|tr -d '=\n'
After disclosing Disclosures from sd-jwt, JWT body will be:
{
"iss":"etsi/PNOEE-30303039914",
"aud":["https://css.ria.ee:443/key-shares/9EE90F2D-D946-4D54-9C3D-F4C68F7FFAE3?nonce=59b314d4815f21f73a0b9168cecbd5773cc694b6"]
}
Other rules to validate auth ticket:
TODO: https://open-eid.github.io/CDOC2/2.0/03_system_architecture
For additional details see tests in src/test/java/