]> err.no Git - yubikey-personalization/blob - ykpers-json.c
Merge tag 'v1.15.1'
[yubikey-personalization] / ykpers-json.c
1 /* -*- mode:C; c-file-style: "bsd" -*- */
2 /*
3  * Copyright (c) 2013 Yubico AB
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *
13  *     * Redistributions in binary form must reproduce the above
14  *       copyright notice, this list of conditions and the following
15  *       disclaimer in the documentation and/or other materials provided
16  *       with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "ykpers_lcl.h"
32 #include "ykpers-json.h"
33
34 #include <yubikey.h>
35
36 #include <json.h>
37 #include <string.h>
38
39 int _ykp_json_export_cfg(const YKP_CONFIG *cfg, char *json, size_t len) {
40         json_object *jobj = json_object_new_object();
41         json_object *yprod_json = json_object_new_object();
42         json_object *options_json = json_object_new_object();
43         if(cfg) {
44                 YK_CONFIG ycfg = cfg->ykcore_config;
45
46                 int mode = MODE_OTP_YUBICO;
47                 struct map_st *p;
48                 json_object *target_config = NULL;
49                 json_object *prot_obj = NULL;
50                 int protection = ykp_get_acccode_type(cfg);
51
52                 if((ycfg.tktFlags & TKTFLAG_OATH_HOTP) == TKTFLAG_OATH_HOTP){
53                         if((ycfg.cfgFlags & CFGFLAG_CHAL_HMAC) == CFGFLAG_CHAL_HMAC) {
54                                 mode = MODE_CHAL_HMAC;
55                         } else if((ycfg.cfgFlags & CFGFLAG_CHAL_YUBICO) == CFGFLAG_CHAL_YUBICO) {
56                                 mode = MODE_CHAL_YUBICO;
57                         } else {
58                                 mode = MODE_OATH_HOTP;
59                         }
60                 }
61                 else if((ycfg.cfgFlags & CFGFLAG_STATIC_TICKET) == CFGFLAG_STATIC_TICKET) {
62                         mode = MODE_STATIC_TICKET;
63                 }
64
65                 for(p = _modes_map; p->flag; p++) {
66                         if(p->flag == mode) {
67                                 json_object *jmode = json_object_new_string(p->json_text);
68                                 json_object_object_add(yprod_json, "mode", jmode);
69                                 break;
70                         }
71                 }
72
73                 if(cfg->command == SLOT_CONFIG) {
74                         target_config = json_object_new_int(1);
75                 } else if(cfg->command == SLOT_CONFIG2) {
76                         target_config = json_object_new_int(2);
77                 }
78                 if(target_config) {
79                         json_object_object_add(yprod_json, "targetConfig", target_config);
80                 }
81
82                 if(protection == YKP_ACCCODE_NONE) {
83                         prot_obj = json_object_new_string("none");
84                 } else if(protection == YKP_ACCCODE_RANDOM) {
85                         prot_obj = json_object_new_string("random");
86                 } else if(protection == YKP_ACCCODE_SERIAL) {
87                         prot_obj = json_object_new_string("id");
88                 }
89                 if(prot_obj) {
90                         json_object_object_add(yprod_json, "protection", prot_obj);
91                 }
92
93                 json_object_object_add(jobj, "yubiProdConfig", yprod_json);
94                 json_object_object_add(yprod_json, "options", options_json);
95
96
97                 if(ycfg.fixedSize != 0 && mode != MODE_STATIC_TICKET) {
98                         json_object *jPrefix;
99                         char prefix[5] = {0};
100
101                         json_object *scope;
102                         if(mode == MODE_OTP_YUBICO &&
103                                         ycfg.fixed[0] == 0x00 && ycfg.fixed[1] == 0x00) {
104                                 scope = json_object_new_string("yubiCloud");
105                         } else {
106                                 scope = json_object_new_string("privatePrefix");
107                         }
108                         json_object_object_add(yprod_json, "scope", scope);
109
110                         yubikey_modhex_encode(prefix, (const char*)ycfg.fixed, 2);
111                         if(mode == MODE_OATH_HOTP) {
112                                 int flag = ycfg.cfgFlags & CFGFLAG_OATH_FIXED_MODHEX;
113                                 json_object *fixed_modhex = json_object_new_boolean(
114                                                 flag == CFGFLAG_OATH_FIXED_MODHEX ? 1 : 0);
115                                 json_object_object_add(options_json, "fixedModhex", fixed_modhex);
116
117                                 if(flag == 0) {
118                                         yubikey_hex_encode(prefix, (const char*)ycfg.fixed, 2);
119                                 } else if(flag == CFGFLAG_OATH_FIXED_MODHEX1) {
120                                         yubikey_hex_encode(prefix + 2, (const char*)ycfg.fixed + 1, 1);
121                                 }
122                         }
123                         jPrefix = json_object_new_string(prefix);
124                         json_object_object_add(yprod_json, "prefix", jPrefix);
125                 } else if(mode != MODE_STATIC_TICKET) {
126                         json_object *scope = json_object_new_string("noPublicId");
127                         json_object_object_add(yprod_json, "scope", scope);
128                 }
129
130                 if(mode == MODE_OATH_HOTP) {
131                         json_object *oathDigits;
132                         json_object *randomSeed;
133                         if((ycfg.cfgFlags & CFGFLAG_OATH_HOTP8) == CFGFLAG_OATH_HOTP8) {
134                                 oathDigits = json_object_new_int(8);
135                         } else {
136                                 oathDigits = json_object_new_int(6);
137                         }
138                         json_object_object_add(options_json, "oathDigits", oathDigits);
139
140                         if((ycfg.uid[5] == 0x01 || ycfg.uid[5] == 0x00) && ycfg.uid[4] == 0x00) {
141                                 json_object *fixedSeedvalue = json_object_new_int(ycfg.uid[5] << 4);
142                                 json_object_object_add(options_json, "fixedSeedvalue", fixedSeedvalue);
143                                 randomSeed = json_object_new_boolean(0);
144                         } else {
145                                 randomSeed = json_object_new_boolean(1);
146                         }
147                         json_object_object_add(options_json, "randomSeed", randomSeed);
148                 }
149
150                 for(p = _ticket_flags_map; p->flag; p++) {
151                         if(!p->json_text) {
152                                 continue;
153                         }
154                         if(p->mode && (mode & p->mode) == mode) {
155                                 int set = (ycfg.tktFlags & p->flag) == p->flag;
156                                 json_object *jsetting = json_object_new_boolean(set);
157                                 json_object_object_add(options_json, p->json_text, jsetting);
158                         }
159                 }
160
161                 for(p = _config_flags_map; p->flag; p++) {
162                         if(!p->json_text) {
163                                 continue;
164                         }
165                         if(p->mode && (mode & p->mode) == mode) {
166                                 int set = (ycfg.cfgFlags & p->flag) == p->flag;
167                                 json_object *jsetting = json_object_new_boolean(set);
168                                 json_object_object_add(options_json, p->json_text, jsetting);
169                         }
170                 }
171
172                 for(p = _extended_flags_map; p->flag; p++) {
173                         if(!p->json_text) {
174                                 continue;
175                         }
176                         if(p->mode && (mode & p->mode) == mode) {
177                                 int set = (ycfg.extFlags & p->flag) == p->flag;
178                                 json_object *jsetting = json_object_new_boolean(set);
179                                 json_object_object_add(options_json, p->json_text, jsetting);
180                         }
181                 }
182         }
183
184 #ifdef HAVE_JSON_OBJECT_TO_JSON_STRING_EXT
185         strncpy(json, json_object_to_json_string_ext(jobj, JSON_C_TO_STRING_PRETTY), len);
186 #else
187         strncpy(json, json_object_to_json_string(jobj), len);
188 #endif
189
190         /* free the root object, will free all children */
191         json_object_put(jobj);
192         return strlen(json);
193 }
194
195 int _ykp_json_import_cfg(YKP_CONFIG *cfg, const char *json, size_t len) {
196         int ret_code = 0;
197         if(cfg) {
198                 json_object *jobj = json_tokener_parse(json);
199                 json_object *yprod_json = json_object_object_get(jobj, "yubiProdConfig");
200                 json_object *jmode = json_object_object_get(yprod_json, "mode");
201                 json_object *options = json_object_object_get(yprod_json, "options");
202                 json_object *jtarget;
203                 const char *raw_mode;
204                 int mode = MODE_OTP_YUBICO;
205                 struct map_st *p;
206
207                 if(!jobj || !yprod_json || !jmode || !options) {
208                         ykp_errno = YKP_EINVAL;
209                         goto out;
210                 }
211
212                 jtarget = json_object_object_get(yprod_json, "targetConfig");
213                 if(jtarget) {
214                         int target_config = json_object_get_int(jtarget);
215                         int command;
216                         if(target_config == 1) {
217                                 command = SLOT_CONFIG;
218                         } else if(target_config == 2) {
219                                 command = SLOT_CONFIG2;
220                         } else {
221                                 ykp_errno = YKP_EINVAL;
222                                 goto out;
223                         }
224                         if(ykp_command(cfg) == 0) {
225                                 ykp_configure_command(cfg, command);
226                         } else if(ykp_command(cfg) != command) {
227                                 ykp_errno = YKP_EINVAL;
228                                 goto out;
229                         }
230                 }
231
232                 raw_mode = json_object_get_string(jmode);
233
234                 for(p = _modes_map; p->flag; p++) {
235                         if(strcmp(raw_mode, p->json_text) == 0) {
236                                 mode = p->flag;
237                                 break;
238                         }
239                 }
240
241
242                 if(mode == MODE_OATH_HOTP) {
243                         json_object *jdigits = json_object_object_get(options, "oathDigits");
244                         json_object *jrandom = json_object_object_get(options, "randomSeed");
245
246                         ykp_set_tktflag_OATH_HOTP(cfg, true);
247                         if(jdigits) {
248                                 int digits = json_object_get_int(jdigits);
249                                 if(digits == 8) {
250                                         ykp_set_cfgflag_OATH_HOTP8(cfg, true);
251                                 }
252                         }
253                         if(jrandom) {
254                                 int random = json_object_get_boolean(jrandom);
255                                 int seed = 0;
256                                 if(random == 1) {
257                                         /* XXX: add random seed.. */
258                                 } else {
259                                         json_object *jseed = json_object_object_get(options, "fixedSeedvalue");
260                                         if(jseed) {
261                                                 seed = json_object_get_int(jseed);
262                                         }
263                                 }
264                                 ykp_set_oath_imf(cfg, (long unsigned int)seed);
265                         }
266                 } else if(mode == MODE_CHAL_HMAC) {
267                         ykp_set_tktflag_CHAL_RESP(cfg, true);
268                         ykp_set_cfgflag_CHAL_HMAC(cfg, true);
269                 } else if(mode == MODE_CHAL_YUBICO) {
270                         ykp_set_tktflag_CHAL_RESP(cfg, true);
271                         ykp_set_cfgflag_CHAL_YUBICO(cfg, true);
272                 } else if(mode == MODE_STATIC_TICKET) {
273                         ykp_set_cfgflag_STATIC_TICKET(cfg, true);
274                 }
275
276                 for(p = _ticket_flags_map; p->flag; p++) {
277                         if(!p->json_text) {
278                                 continue;
279                         }
280                         if(p->mode && (mode & p->mode) == mode) {
281                                 json_object *joption = json_object_object_get(options, p->json_text);
282                                 if(joption && json_object_get_type(joption) == json_type_boolean) {
283                                         int value = json_object_get_boolean(joption);
284                                         if(value == 1) {
285                                                 p->setter(cfg, true);
286                                         }
287                                 }
288                         }
289                 }
290
291                 for(p = _config_flags_map; p->flag; p++) {
292                         if(!p->json_text) {
293                                 continue;
294                         }
295                         if(p->mode && (mode & p->mode) == mode) {
296                                 json_object *joption = json_object_object_get(options, p->json_text);
297                                 if(joption && json_object_get_type(joption) == json_type_boolean) {
298                                         int value = json_object_get_boolean(joption);
299                                         if(value == 1) {
300                                                 p->setter(cfg, true);
301                                         }
302                                 }
303                         }
304                 }
305
306                 for(p = _extended_flags_map; p->flag; p++) {
307                         if(!p->json_text) {
308                                 continue;
309                         }
310                         if(p->mode && (mode & p->mode) == mode) {
311                                 json_object *joption = json_object_object_get(options, p->json_text);
312                                 if(joption && json_object_get_type(joption) == json_type_boolean) {
313                                         int value = json_object_get_boolean(joption);
314                                         if(value == 1) {
315                                                 p->setter(cfg, true);
316                                         }
317                                 }
318                         }
319                 }
320
321                 ret_code = 1;
322 out:
323                 if(jobj) {
324                         json_object_put(jobj);
325                 }
326         }
327         ykp_errno = YKP_EINVAL;
328         return ret_code;
329 }
330