1 /* -*- mode:C; c-file-style: "bsd" -*- */
3 * Copyright (c) 2013 Yubico AB
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
31 #include "ykpers_lcl.h"
32 #include "ykpers-json.h"
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();
44 YK_CONFIG ycfg = cfg->ykcore_config;
46 int mode = MODE_OTP_YUBICO;
48 json_object *target_config = NULL;
49 json_object *prot_obj = NULL;
50 int protection = ykp_get_acccode_type(cfg);
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;
58 mode = MODE_OATH_HOTP;
61 else if((ycfg.cfgFlags & CFGFLAG_STATIC_TICKET) == CFGFLAG_STATIC_TICKET) {
62 mode = MODE_STATIC_TICKET;
65 for(p = _modes_map; p->flag; p++) {
67 json_object *jmode = json_object_new_string(p->json_text);
68 json_object_object_add(yprod_json, "mode", jmode);
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);
79 json_object_object_add(yprod_json, "targetConfig", target_config);
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");
90 json_object_object_add(yprod_json, "protection", prot_obj);
93 json_object_object_add(jobj, "yubiProdConfig", yprod_json);
94 json_object_object_add(yprod_json, "options", options_json);
97 if(ycfg.fixedSize != 0 && mode != MODE_STATIC_TICKET) {
102 if(mode == MODE_OTP_YUBICO &&
103 ycfg.fixed[0] == 0x00 && ycfg.fixed[1] == 0x00) {
104 scope = json_object_new_string("yubiCloud");
106 scope = json_object_new_string("privatePrefix");
108 json_object_object_add(yprod_json, "scope", scope);
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);
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);
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);
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);
136 oathDigits = json_object_new_int(6);
138 json_object_object_add(options_json, "oathDigits", oathDigits);
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);
145 randomSeed = json_object_new_boolean(1);
147 json_object_object_add(options_json, "randomSeed", randomSeed);
150 for(p = _ticket_flags_map; p->flag; p++) {
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);
161 for(p = _config_flags_map; p->flag; p++) {
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);
172 for(p = _extended_flags_map; p->flag; p++) {
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);
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);
187 strncpy(json, json_object_to_json_string(jobj), len);
190 /* free the root object, will free all children */
191 json_object_put(jobj);
195 int _ykp_json_import_cfg(YKP_CONFIG *cfg, const char *json, size_t len) {
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;
207 if(!jobj || !yprod_json || !jmode || !options) {
208 ykp_errno = YKP_EINVAL;
212 jtarget = json_object_object_get(yprod_json, "targetConfig");
214 int target_config = json_object_get_int(jtarget);
216 if(target_config == 1) {
217 command = SLOT_CONFIG;
218 } else if(target_config == 2) {
219 command = SLOT_CONFIG2;
221 ykp_errno = YKP_EINVAL;
224 if(ykp_command(cfg) == 0) {
225 ykp_configure_command(cfg, command);
226 } else if(ykp_command(cfg) != command) {
227 ykp_errno = YKP_EINVAL;
232 raw_mode = json_object_get_string(jmode);
234 for(p = _modes_map; p->flag; p++) {
235 if(strcmp(raw_mode, p->json_text) == 0) {
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");
246 ykp_set_tktflag_OATH_HOTP(cfg, true);
248 int digits = json_object_get_int(jdigits);
250 ykp_set_cfgflag_OATH_HOTP8(cfg, true);
254 int random = json_object_get_boolean(jrandom);
257 /* XXX: add random seed.. */
259 json_object *jseed = json_object_object_get(options, "fixedSeedvalue");
261 seed = json_object_get_int(jseed);
264 ykp_set_oath_imf(cfg, (long unsigned int)seed);
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);
276 for(p = _ticket_flags_map; p->flag; p++) {
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);
285 p->setter(cfg, true);
291 for(p = _config_flags_map; p->flag; p++) {
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);
300 p->setter(cfg, true);
306 for(p = _extended_flags_map; p->flag; p++) {
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);
315 p->setter(cfg, true);
324 json_object_put(jobj);
327 ykp_errno = YKP_EINVAL;