1#![doc = include_str!("../README.md")]
2
3use credential_exchange_format::B64Url;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Serialize, Deserialize)]
7#[serde(rename_all = "camelCase")]
8pub struct ExportRequest {
9 pub version: Version,
10 pub hpke: Vec<HpkeParameters>,
11 pub importer: String,
12 #[serde(default, skip_serializing_if = "Option::is_none")]
13 pub credential_types: Option<Vec<CredentialType>>,
14 #[serde(default, skip_serializing_if = "Option::is_none")]
15 pub known_extensions: Option<Vec<KnownExtension>>,
16}
17
18#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
19#[serde(from = "u8", into = "u8")]
20pub enum Version {
21 V0,
22 Unknown(u8),
23}
24
25impl From<u8> for Version {
26 fn from(value: u8) -> Self {
27 match value {
28 0 => Version::V0,
29 v => Version::Unknown(v),
30 }
31 }
32}
33
34impl From<Version> for u8 {
35 fn from(value: Version) -> Self {
36 match value {
37 Version::V0 => 0,
38 Version::Unknown(v) => v,
39 }
40 }
41}
42
43#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
44#[serde(rename_all = "kebab-case")]
45pub enum CredentialType {
46 BasicAuth,
47 Passkey,
48 Totp,
49 Note,
50 File,
51 Address,
52 CreditCard,
53 DriverLicense,
54 ItemReference,
55 IdentityDocument,
56 Passport,
57 PersonName,
58 SshKey,
59 ApiKey,
60 #[serde(untagged)]
61 Unknown(String),
62}
63
64#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
65#[serde(rename_all = "kebab-case")]
66pub enum KnownExtension {
67 Shared,
68 #[serde(untagged)]
69 Unknown(String),
70}
71
72#[derive(Clone, Debug, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct HpkeParameters {
75 pub mode: HpkeMode,
76 pub kem: HpkeKem,
77 pub kdf: HpkeKdf,
78 pub aead: HpkeAead,
79 pub key: Option<jose_jwk::Jwk>,
80}
81
82impl PartialEq for HpkeParameters {
83 fn eq(&self, other: &Self) -> bool {
84 self.mode == other.mode
85 && self.kem == other.kem
86 && self.kdf == other.kdf
87 && self.aead == other.aead
88 }
91}
92
93#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
94#[serde(rename_all = "kebab-case")]
95pub enum HpkeMode {
96 Base,
97 Psk,
98 Auth,
99 AuthPsk,
100 #[serde(untagged)]
101 Unknown(String),
102}
103
104#[derive(Debug, Serialize, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct ExportResponse {
107 pub version: Version,
108 pub hpke: HpkeParameters,
109 pub exporter: String,
110 pub payload: B64Url,
111}
112
113#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
114#[serde(from = "u16", into = "u16")]
115pub enum HpkeKem {
116 Reserved,
117 DhP256,
118 DhP384,
119 DhP521,
120 DhCP256,
121 DhCP384,
122 DhCP521,
123 DhSecP256K1,
124 DhX25519,
125 DhX448,
126 X25519Kyber768Draft00,
127 Unasssigned(u16),
128}
129
130impl From<HpkeKem> for u16 {
131 fn from(value: HpkeKem) -> Self {
132 match value {
133 HpkeKem::Reserved => 0x0000,
134 HpkeKem::DhP256 => 0x0010,
135 HpkeKem::DhP384 => 0x0011,
136 HpkeKem::DhP521 => 0x0012,
137 HpkeKem::DhCP256 => 0x0013,
138 HpkeKem::DhCP384 => 0x0014,
139 HpkeKem::DhCP521 => 0x0015,
140 HpkeKem::DhSecP256K1 => 0x0016,
141 HpkeKem::DhX25519 => 0x0020,
142 HpkeKem::DhX448 => 0x0021,
143 HpkeKem::X25519Kyber768Draft00 => 0x0030,
144 HpkeKem::Unasssigned(u) => u,
145 }
146 }
147}
148
149impl From<u16> for HpkeKem {
150 fn from(value: u16) -> Self {
151 match value {
152 0x0000 => HpkeKem::Reserved,
153 u @ 0x0001..=0x000F => HpkeKem::Unasssigned(u),
154 0x0010 => HpkeKem::DhP256,
155 0x0011 => HpkeKem::DhP384,
156 0x0012 => HpkeKem::DhP521,
157 0x0013 => HpkeKem::DhCP256,
158 0x0014 => HpkeKem::DhCP384,
159 0x0015 => HpkeKem::DhCP521,
160 0x0016 => HpkeKem::DhSecP256K1,
161 u @ 0x0017..=0x001F => HpkeKem::Unasssigned(u),
162 0x0020 => HpkeKem::DhX25519,
163 0x0021 => HpkeKem::DhX448,
164 u @ 0x0022..=0x002F => HpkeKem::Unasssigned(u),
165 0x0030 => HpkeKem::X25519Kyber768Draft00,
166 u @ 0x0031..=0xFFFF => HpkeKem::Unasssigned(u),
167 }
168 }
169}
170#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
171#[serde(from = "u16", into = "u16")]
172pub enum HpkeKdf {
173 Reserved,
174 HkdfSha256,
175 HkdfSha384,
176 HkdfSha512,
177 Unassigned(u16),
178}
179
180impl From<HpkeKdf> for u16 {
181 fn from(value: HpkeKdf) -> Self {
182 match value {
183 HpkeKdf::Reserved => 0x0000,
184 HpkeKdf::HkdfSha256 => 0x0001,
185 HpkeKdf::HkdfSha384 => 0x0002,
186 HpkeKdf::HkdfSha512 => 0x0003,
187 HpkeKdf::Unassigned(u) => u,
188 }
189 }
190}
191
192impl From<u16> for HpkeKdf {
193 fn from(value: u16) -> HpkeKdf {
194 match value {
195 0x0000 => HpkeKdf::Reserved,
196 0x0001 => HpkeKdf::HkdfSha256,
197 0x0002 => HpkeKdf::HkdfSha384,
198 0x0003 => HpkeKdf::HkdfSha512,
199 u @ 0x0004..=0xFFFF => HpkeKdf::Unassigned(u),
200 }
201 }
202}
203
204#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
205#[serde(from = "u16", into = "u16")]
206pub enum HpkeAead {
207 Reserved,
208 Aes128Gcm,
209 Aes256Gcm,
210 ChaCha20Poly1305,
211 Unassigned(u16),
212 ExportOnly,
213}
214
215impl From<HpkeAead> for u16 {
216 fn from(value: HpkeAead) -> Self {
217 match value {
218 HpkeAead::Reserved => 0x0000,
219 HpkeAead::Aes128Gcm => 0x0001,
220 HpkeAead::Aes256Gcm => 0x0002,
221 HpkeAead::ChaCha20Poly1305 => 0x0003,
222 HpkeAead::Unassigned(u) => u,
223 HpkeAead::ExportOnly => 0xFFFF,
224 }
225 }
226}
227
228impl From<u16> for HpkeAead {
229 fn from(value: u16) -> HpkeAead {
230 match value {
231 0x0000 => HpkeAead::Reserved,
232 0x0001 => HpkeAead::Aes128Gcm,
233 0x0002 => HpkeAead::Aes256Gcm,
234 0x0003 => HpkeAead::ChaCha20Poly1305,
235 u @ 0x0004..=0xFFFE => HpkeAead::Unassigned(u),
236 0xFFFF => HpkeAead::ExportOnly,
237 }
238 }
239}
240
241pub struct ErrorResponse {
242 pub version: Version,
243 pub error: ErrorCode,
244}
245
246#[derive(Debug)]
247pub enum ErrorCode {
248 UserCanceled,
250 IncompatibleHpkeParameters,
252 MissingImporterKey,
255 IncorrectImporterKeyEncoding,
257 UnsupportedVersion,
259 InvalidJson,
261 ForbiddenAction,
264}