1*f0865ec9SKyle Evans /* 2*f0865ec9SKyle Evans * Copyright (C) 2017 - This file is part of libecc project 3*f0865ec9SKyle Evans * 4*f0865ec9SKyle Evans * Authors: 5*f0865ec9SKyle Evans * Ryad BENADJILA <ryadbenadjila@gmail.com> 6*f0865ec9SKyle Evans * Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr> 7*f0865ec9SKyle Evans * Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr> 8*f0865ec9SKyle Evans * 9*f0865ec9SKyle Evans * Contributors: 10*f0865ec9SKyle Evans * Nicolas VIVET <nicolas.vivet@ssi.gouv.fr> 11*f0865ec9SKyle Evans * Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr> 12*f0865ec9SKyle Evans * 13*f0865ec9SKyle Evans * This software is licensed under a dual BSD and GPL v2 license. 14*f0865ec9SKyle Evans * See LICENSE file at the root folder of the project. 15*f0865ec9SKyle Evans */ 16*f0865ec9SKyle Evans 17*f0865ec9SKyle Evans #include <libecc/libsig.h> 18*f0865ec9SKyle Evans 19*f0865ec9SKyle Evans #ifdef WITH_STDLIB 20*f0865ec9SKyle Evans #include <string.h> 21*f0865ec9SKyle Evans #include <stdlib.h> 22*f0865ec9SKyle Evans #include <stdio.h> 23*f0865ec9SKyle Evans #include <errno.h> 24*f0865ec9SKyle Evans #endif 25*f0865ec9SKyle Evans 26*f0865ec9SKyle Evans #define HDR_MAGIC 0x34215609 27*f0865ec9SKyle Evans 28*f0865ec9SKyle Evans typedef enum { 29*f0865ec9SKyle Evans IMAGE_TYPE_UNKNOWN = 0, 30*f0865ec9SKyle Evans IMAGE_TYPE0 = 1, 31*f0865ec9SKyle Evans IMAGE_TYPE1 = 2, 32*f0865ec9SKyle Evans IMAGE_TYPE2 = 3, 33*f0865ec9SKyle Evans IMAGE_TYPE3 = 4, 34*f0865ec9SKyle Evans /* Info: You can add more image header types */ 35*f0865ec9SKyle Evans } image_type; 36*f0865ec9SKyle Evans 37*f0865ec9SKyle Evans /* Generic header to prepend data */ 38*f0865ec9SKyle Evans typedef struct { 39*f0865ec9SKyle Evans u32 magic; /* header header */ 40*f0865ec9SKyle Evans u32 type; /* Type of the signed image */ 41*f0865ec9SKyle Evans u32 version; /* Version */ 42*f0865ec9SKyle Evans u32 len; /* length of data after header */ 43*f0865ec9SKyle Evans u32 siglen; /* length of sig (on header + data) */ 44*f0865ec9SKyle Evans } ATTRIBUTE_PACKED metadata_hdr; 45*f0865ec9SKyle Evans 46*f0865ec9SKyle Evans /* Max stack working buffer size */ 47*f0865ec9SKyle Evans #define MAX_BUF_LEN 8192 48*f0865ec9SKyle Evans 49*f0865ec9SKyle Evans typedef enum { 50*f0865ec9SKyle Evans RAWBIN, 51*f0865ec9SKyle Evans DOTH, 52*f0865ec9SKyle Evans } export_file_type; 53*f0865ec9SKyle Evans 54*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int export_private_key(FILE * file, const char *name, 55*f0865ec9SKyle Evans const ec_priv_key *priv_key, 56*f0865ec9SKyle Evans export_file_type file_type) 57*f0865ec9SKyle Evans { 58*f0865ec9SKyle Evans u8 export_buf_size, priv_key_buf[EC_STRUCTURED_PRIV_KEY_MAX_EXPORT_SIZE]; 59*f0865ec9SKyle Evans size_t written; 60*f0865ec9SKyle Evans int ret; 61*f0865ec9SKyle Evans u32 i; 62*f0865ec9SKyle Evans 63*f0865ec9SKyle Evans MUST_HAVE(file != NULL, ret, err); 64*f0865ec9SKyle Evans 65*f0865ec9SKyle Evans ret = priv_key_check_initialized(priv_key); 66*f0865ec9SKyle Evans if (ret) { 67*f0865ec9SKyle Evans printf("Error checking private key\n"); 68*f0865ec9SKyle Evans ret = -1; 69*f0865ec9SKyle Evans goto err; 70*f0865ec9SKyle Evans } 71*f0865ec9SKyle Evans 72*f0865ec9SKyle Evans /* Serialize the private key to a buffer */ 73*f0865ec9SKyle Evans export_buf_size = EC_STRUCTURED_PRIV_KEY_EXPORT_SIZE(priv_key); 74*f0865ec9SKyle Evans ret = ec_structured_priv_key_export_to_buf(priv_key, priv_key_buf, 75*f0865ec9SKyle Evans export_buf_size); 76*f0865ec9SKyle Evans if (ret) { 77*f0865ec9SKyle Evans printf("Error exporting private key to buffer\n"); 78*f0865ec9SKyle Evans ret = -1; 79*f0865ec9SKyle Evans goto err; 80*f0865ec9SKyle Evans } 81*f0865ec9SKyle Evans 82*f0865ec9SKyle Evans /* Export the private key to the file */ 83*f0865ec9SKyle Evans switch (file_type) { 84*f0865ec9SKyle Evans case DOTH: 85*f0865ec9SKyle Evans MUST_HAVE(name != NULL, ret, err); 86*f0865ec9SKyle Evans fprintf(file, "const char %s[] = { ", name); 87*f0865ec9SKyle Evans for (i = 0; i < export_buf_size; i++) { 88*f0865ec9SKyle Evans fprintf(file, "0x%02x", priv_key_buf[i]); 89*f0865ec9SKyle Evans fprintf(file, ", "); 90*f0865ec9SKyle Evans } 91*f0865ec9SKyle Evans fprintf(file, "};\n"); 92*f0865ec9SKyle Evans ret = 0; 93*f0865ec9SKyle Evans break; 94*f0865ec9SKyle Evans case RAWBIN: 95*f0865ec9SKyle Evans written = fwrite(priv_key_buf, 1, export_buf_size, file); 96*f0865ec9SKyle Evans if(written != export_buf_size){ 97*f0865ec9SKyle Evans ret = -1; 98*f0865ec9SKyle Evans goto err; 99*f0865ec9SKyle Evans } 100*f0865ec9SKyle Evans ret = 0; 101*f0865ec9SKyle Evans break; 102*f0865ec9SKyle Evans default: 103*f0865ec9SKyle Evans ret = -1; 104*f0865ec9SKyle Evans } 105*f0865ec9SKyle Evans 106*f0865ec9SKyle Evans err: 107*f0865ec9SKyle Evans return ret; 108*f0865ec9SKyle Evans } 109*f0865ec9SKyle Evans 110*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int export_public_key(FILE * file, const char *name, 111*f0865ec9SKyle Evans const ec_pub_key *pub_key, 112*f0865ec9SKyle Evans export_file_type file_type) 113*f0865ec9SKyle Evans { 114*f0865ec9SKyle Evans u8 pub_key_buf[EC_STRUCTURED_PUB_KEY_MAX_EXPORT_SIZE]; 115*f0865ec9SKyle Evans u8 export_buf_size; 116*f0865ec9SKyle Evans int ret; 117*f0865ec9SKyle Evans u32 i; 118*f0865ec9SKyle Evans size_t written; 119*f0865ec9SKyle Evans 120*f0865ec9SKyle Evans MUST_HAVE(file != NULL, ret, err); 121*f0865ec9SKyle Evans ret = pub_key_check_initialized(pub_key); 122*f0865ec9SKyle Evans if (ret) { 123*f0865ec9SKyle Evans printf("Error checking public key\n"); 124*f0865ec9SKyle Evans ret = -1; 125*f0865ec9SKyle Evans goto err; 126*f0865ec9SKyle Evans } 127*f0865ec9SKyle Evans 128*f0865ec9SKyle Evans /* Serialize the public key to a buffer */ 129*f0865ec9SKyle Evans export_buf_size = EC_STRUCTURED_PUB_KEY_EXPORT_SIZE(pub_key); 130*f0865ec9SKyle Evans ret = ec_structured_pub_key_export_to_buf(pub_key, pub_key_buf, 131*f0865ec9SKyle Evans export_buf_size); 132*f0865ec9SKyle Evans if (ret) { 133*f0865ec9SKyle Evans printf("Error exporting public key to buffer\n"); 134*f0865ec9SKyle Evans ret = -1; 135*f0865ec9SKyle Evans goto err; 136*f0865ec9SKyle Evans } 137*f0865ec9SKyle Evans 138*f0865ec9SKyle Evans /* Export the public key to the file */ 139*f0865ec9SKyle Evans switch (file_type) { 140*f0865ec9SKyle Evans case DOTH: 141*f0865ec9SKyle Evans MUST_HAVE(name != NULL, ret, err); 142*f0865ec9SKyle Evans fprintf(file, "const char %s[] = { ", name); 143*f0865ec9SKyle Evans for (i = 0; i < export_buf_size; i++) { 144*f0865ec9SKyle Evans fprintf(file, "0x%02x", pub_key_buf[i]); 145*f0865ec9SKyle Evans if (i != export_buf_size) { 146*f0865ec9SKyle Evans fprintf(file, ", "); 147*f0865ec9SKyle Evans } 148*f0865ec9SKyle Evans } 149*f0865ec9SKyle Evans fprintf(file, "};\n"); 150*f0865ec9SKyle Evans ret = 0; 151*f0865ec9SKyle Evans break; 152*f0865ec9SKyle Evans case RAWBIN: 153*f0865ec9SKyle Evans written = fwrite(pub_key_buf, 1, export_buf_size, file); 154*f0865ec9SKyle Evans if(written != export_buf_size){ 155*f0865ec9SKyle Evans ret = -1; 156*f0865ec9SKyle Evans goto err; 157*f0865ec9SKyle Evans } 158*f0865ec9SKyle Evans ret = 0; 159*f0865ec9SKyle Evans break; 160*f0865ec9SKyle Evans default: 161*f0865ec9SKyle Evans ret = -1; 162*f0865ec9SKyle Evans } 163*f0865ec9SKyle Evans 164*f0865ec9SKyle Evans err: 165*f0865ec9SKyle Evans return ret; 166*f0865ec9SKyle Evans } 167*f0865ec9SKyle Evans 168*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int string_to_params(const char *ec_name, const char *ec_sig_name, 169*f0865ec9SKyle Evans ec_alg_type * sig_type, 170*f0865ec9SKyle Evans const ec_str_params ** ec_str_p, 171*f0865ec9SKyle Evans const char *hash_name, hash_alg_type * hash_type) 172*f0865ec9SKyle Evans { 173*f0865ec9SKyle Evans const ec_str_params *curve_params; 174*f0865ec9SKyle Evans const ec_sig_mapping *sm; 175*f0865ec9SKyle Evans const hash_mapping *hm; 176*f0865ec9SKyle Evans u32 curve_name_len; 177*f0865ec9SKyle Evans int ret; 178*f0865ec9SKyle Evans 179*f0865ec9SKyle Evans if (sig_type != NULL) { 180*f0865ec9SKyle Evans /* Get sig type from signature alg name */ 181*f0865ec9SKyle Evans ret = get_sig_by_name(ec_sig_name, &sm); 182*f0865ec9SKyle Evans if ((ret) || (!sm)) { 183*f0865ec9SKyle Evans ret = -1; 184*f0865ec9SKyle Evans printf("Error: signature type %s is unknown!\n", 185*f0865ec9SKyle Evans ec_sig_name); 186*f0865ec9SKyle Evans goto err; 187*f0865ec9SKyle Evans } 188*f0865ec9SKyle Evans *sig_type = sm->type; 189*f0865ec9SKyle Evans } 190*f0865ec9SKyle Evans 191*f0865ec9SKyle Evans if (ec_str_p != NULL) { 192*f0865ec9SKyle Evans /* Get curve params from curve name */ 193*f0865ec9SKyle Evans ret = local_strlen((const char *)ec_name, &curve_name_len); EG(ret, err); 194*f0865ec9SKyle Evans curve_name_len += 1; 195*f0865ec9SKyle Evans if(curve_name_len > 255){ 196*f0865ec9SKyle Evans /* Sanity check */ 197*f0865ec9SKyle Evans ret = -1; 198*f0865ec9SKyle Evans goto err; 199*f0865ec9SKyle Evans } 200*f0865ec9SKyle Evans ret = ec_get_curve_params_by_name((const u8 *)ec_name, 201*f0865ec9SKyle Evans (u8)curve_name_len, &curve_params); 202*f0865ec9SKyle Evans if ((ret) || (!curve_params)) { 203*f0865ec9SKyle Evans ret = -1; 204*f0865ec9SKyle Evans printf("Error: EC curve %s is unknown!\n", ec_name); 205*f0865ec9SKyle Evans goto err; 206*f0865ec9SKyle Evans } 207*f0865ec9SKyle Evans *ec_str_p = curve_params; 208*f0865ec9SKyle Evans } 209*f0865ec9SKyle Evans 210*f0865ec9SKyle Evans if (hash_type != NULL) { 211*f0865ec9SKyle Evans /* Get hash type from hash alg name */ 212*f0865ec9SKyle Evans ret = get_hash_by_name(hash_name, &hm); 213*f0865ec9SKyle Evans if ((ret) || (!hm)) { 214*f0865ec9SKyle Evans ret = -1; 215*f0865ec9SKyle Evans printf("Error: hash function %s is unknown!\n", 216*f0865ec9SKyle Evans hash_name); 217*f0865ec9SKyle Evans goto err; 218*f0865ec9SKyle Evans } 219*f0865ec9SKyle Evans *hash_type = hm->type; 220*f0865ec9SKyle Evans } 221*f0865ec9SKyle Evans 222*f0865ec9SKyle Evans ret = 0; 223*f0865ec9SKyle Evans 224*f0865ec9SKyle Evans err: 225*f0865ec9SKyle Evans return ret; 226*f0865ec9SKyle Evans } 227*f0865ec9SKyle Evans 228*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int generate_and_export_key_pair(const char *ec_name, 229*f0865ec9SKyle Evans const char *ec_sig_name, 230*f0865ec9SKyle Evans const char *fname_prefix) 231*f0865ec9SKyle Evans { 232*f0865ec9SKyle Evans const ec_str_params *ec_str_p; 233*f0865ec9SKyle Evans char fname[MAX_BUF_LEN]; 234*f0865ec9SKyle Evans char kname[MAX_BUF_LEN]; 235*f0865ec9SKyle Evans const u16 fname_len = sizeof(fname); 236*f0865ec9SKyle Evans const u16 kname_len = sizeof(kname); 237*f0865ec9SKyle Evans u16 prefix_len; 238*f0865ec9SKyle Evans u32 len; 239*f0865ec9SKyle Evans ec_alg_type sig_type; 240*f0865ec9SKyle Evans ec_params params; 241*f0865ec9SKyle Evans ec_key_pair kp; 242*f0865ec9SKyle Evans FILE *file = NULL; 243*f0865ec9SKyle Evans int ret; 244*f0865ec9SKyle Evans 245*f0865ec9SKyle Evans MUST_HAVE(ec_name != NULL, ret, err); 246*f0865ec9SKyle Evans MUST_HAVE(fname_prefix != NULL, ret, err); 247*f0865ec9SKyle Evans MUST_HAVE(ec_sig_name != NULL, ret, err); 248*f0865ec9SKyle Evans 249*f0865ec9SKyle Evans /* Get parameters from pretty names */ 250*f0865ec9SKyle Evans ret = string_to_params(ec_name, ec_sig_name, &sig_type, &ec_str_p, 251*f0865ec9SKyle Evans NULL, NULL); 252*f0865ec9SKyle Evans if (ret) { 253*f0865ec9SKyle Evans ret = -1; 254*f0865ec9SKyle Evans printf("Error: error when importing params\n"); 255*f0865ec9SKyle Evans goto err; 256*f0865ec9SKyle Evans } 257*f0865ec9SKyle Evans 258*f0865ec9SKyle Evans /* Import the parameters */ 259*f0865ec9SKyle Evans ret = import_params(¶ms, ec_str_p); EG(ret, err); 260*f0865ec9SKyle Evans 261*f0865ec9SKyle Evans /* Generate the key pair */ 262*f0865ec9SKyle Evans ret = ec_key_pair_gen(&kp, ¶ms, sig_type); EG(ret, err); 263*f0865ec9SKyle Evans 264*f0865ec9SKyle Evans /* Get the unique affine equivalent representation of the projective point for the public key. 265*f0865ec9SKyle Evans * This avoids ambiguity when exporting the point, and is mostly here 266*f0865ec9SKyle Evans * for compatibility with external libraries. 267*f0865ec9SKyle Evans */ 268*f0865ec9SKyle Evans ret = prj_pt_unique(&(kp.pub_key.y), &(kp.pub_key.y)); EG(ret, err); 269*f0865ec9SKyle Evans 270*f0865ec9SKyle Evans /*************************/ 271*f0865ec9SKyle Evans 272*f0865ec9SKyle Evans /* Export the private key to the raw binary file */ 273*f0865ec9SKyle Evans ret = local_strnlen(fname_prefix, fname_len, &len); EG(ret, err); 274*f0865ec9SKyle Evans MUST_HAVE(len <= 0xffff, ret, err); 275*f0865ec9SKyle Evans prefix_len = (u16)len; 276*f0865ec9SKyle Evans ret = local_memset(fname, 0, fname_len); EG(ret, err); 277*f0865ec9SKyle Evans ret = local_memcpy(fname, fname_prefix, prefix_len); EG(ret, err); 278*f0865ec9SKyle Evans ret = local_strncat(fname, "_private_key.bin", (u32)(fname_len - prefix_len)); EG(ret, err); 279*f0865ec9SKyle Evans file = fopen(fname, "wb"); 280*f0865ec9SKyle Evans if (file == NULL) { 281*f0865ec9SKyle Evans ret = -1; 282*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", fname); 283*f0865ec9SKyle Evans goto err; 284*f0865ec9SKyle Evans } 285*f0865ec9SKyle Evans 286*f0865ec9SKyle Evans ret = export_private_key(file, NULL, &(kp.priv_key), RAWBIN); 287*f0865ec9SKyle Evans if (ret) { 288*f0865ec9SKyle Evans ret = -1; 289*f0865ec9SKyle Evans printf("Error exporting the private key\n"); 290*f0865ec9SKyle Evans goto err; 291*f0865ec9SKyle Evans } 292*f0865ec9SKyle Evans ret = fclose(file); EG(ret, err); 293*f0865ec9SKyle Evans file = NULL; 294*f0865ec9SKyle Evans 295*f0865ec9SKyle Evans /* Export the private key to the .h file */ 296*f0865ec9SKyle Evans ret = local_memset(fname, 0, fname_len); EG(ret, err); 297*f0865ec9SKyle Evans ret = local_memcpy(fname, fname_prefix, prefix_len); EG(ret, err); 298*f0865ec9SKyle Evans ret = local_strncat(fname, "_private_key.h", (u32)(fname_len - prefix_len)); EG(ret, err); 299*f0865ec9SKyle Evans file = fopen(fname, "w"); 300*f0865ec9SKyle Evans if (file == NULL) { 301*f0865ec9SKyle Evans ret = -1; 302*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", fname); 303*f0865ec9SKyle Evans goto err; 304*f0865ec9SKyle Evans } 305*f0865ec9SKyle Evans 306*f0865ec9SKyle Evans snprintf(kname, kname_len, "%s_%s_private_key", ec_name, ec_sig_name); 307*f0865ec9SKyle Evans ret = export_private_key(file, kname, &(kp.priv_key), DOTH); 308*f0865ec9SKyle Evans if (ret) { 309*f0865ec9SKyle Evans ret = -1; 310*f0865ec9SKyle Evans printf("Error: error exporting the private key\n"); 311*f0865ec9SKyle Evans goto err; 312*f0865ec9SKyle Evans } 313*f0865ec9SKyle Evans ret = fclose(file); EG(ret, err); 314*f0865ec9SKyle Evans file = NULL; 315*f0865ec9SKyle Evans 316*f0865ec9SKyle Evans /*************************/ 317*f0865ec9SKyle Evans 318*f0865ec9SKyle Evans /* Export the public key to the raw binary file */ 319*f0865ec9SKyle Evans ret = local_memset(fname, 0, fname_len); EG(ret, err); 320*f0865ec9SKyle Evans ret = local_memcpy(fname, fname_prefix, prefix_len); EG(ret, err); 321*f0865ec9SKyle Evans ret = local_strncat(fname, "_public_key.bin", (u32)(fname_len - prefix_len)); EG(ret, err); 322*f0865ec9SKyle Evans file = fopen(fname, "wb"); 323*f0865ec9SKyle Evans if (file == NULL) { 324*f0865ec9SKyle Evans ret = -1; 325*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", fname); 326*f0865ec9SKyle Evans goto err; 327*f0865ec9SKyle Evans } 328*f0865ec9SKyle Evans ret = export_public_key(file, NULL, &(kp.pub_key), RAWBIN); 329*f0865ec9SKyle Evans if (ret) { 330*f0865ec9SKyle Evans ret = -1; 331*f0865ec9SKyle Evans printf("Error exporting the public key\n"); 332*f0865ec9SKyle Evans goto err; 333*f0865ec9SKyle Evans } 334*f0865ec9SKyle Evans ret = fclose(file); EG(ret, err); 335*f0865ec9SKyle Evans file = NULL; 336*f0865ec9SKyle Evans 337*f0865ec9SKyle Evans /* Export the public key to the .h file */ 338*f0865ec9SKyle Evans ret = local_memset(fname, 0, fname_len); EG(ret, err); 339*f0865ec9SKyle Evans ret = local_memcpy(fname, fname_prefix, prefix_len); EG(ret, err); 340*f0865ec9SKyle Evans ret = local_strncat(fname, "_public_key.h", (u32)(fname_len - prefix_len)); EG(ret, err); 341*f0865ec9SKyle Evans file = fopen(fname, "w"); 342*f0865ec9SKyle Evans if (file == NULL) { 343*f0865ec9SKyle Evans ret = -1; 344*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", fname); 345*f0865ec9SKyle Evans goto err; 346*f0865ec9SKyle Evans } 347*f0865ec9SKyle Evans 348*f0865ec9SKyle Evans snprintf(kname, kname_len, "%s_%s_public_key", ec_name, ec_sig_name); 349*f0865ec9SKyle Evans ret = export_public_key(file, kname, &(kp.pub_key), DOTH); 350*f0865ec9SKyle Evans if (ret) { 351*f0865ec9SKyle Evans ret = -1; 352*f0865ec9SKyle Evans printf("Error exporting the public key\n"); 353*f0865ec9SKyle Evans goto err; 354*f0865ec9SKyle Evans } 355*f0865ec9SKyle Evans ret = fclose(file); EG(ret, err); 356*f0865ec9SKyle Evans file = NULL; 357*f0865ec9SKyle Evans 358*f0865ec9SKyle Evans ret = 0; 359*f0865ec9SKyle Evans 360*f0865ec9SKyle Evans err: 361*f0865ec9SKyle Evans if(file != NULL){ 362*f0865ec9SKyle Evans if(fclose(file)){ 363*f0865ec9SKyle Evans ret = -1; 364*f0865ec9SKyle Evans } 365*f0865ec9SKyle Evans } 366*f0865ec9SKyle Evans return ret; 367*f0865ec9SKyle Evans } 368*f0865ec9SKyle Evans 369*f0865ec9SKyle Evans 370*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int store_sig(const char *in_fname, const char *out_fname, 371*f0865ec9SKyle Evans const u8 *sig, u32 siglen, 372*f0865ec9SKyle Evans ec_alg_type sig_type, hash_alg_type hash_type, 373*f0865ec9SKyle Evans const u8 curve_name[MAX_CURVE_NAME_LEN], 374*f0865ec9SKyle Evans metadata_hdr * hdr) 375*f0865ec9SKyle Evans { 376*f0865ec9SKyle Evans FILE *in_file = NULL, *out_file = NULL; 377*f0865ec9SKyle Evans u8 buf[MAX_BUF_LEN]; 378*f0865ec9SKyle Evans size_t read, written; 379*f0865ec9SKyle Evans int ret; 380*f0865ec9SKyle Evans 381*f0865ec9SKyle Evans MUST_HAVE((in_fname != NULL), ret, err); 382*f0865ec9SKyle Evans MUST_HAVE((out_fname != NULL), ret, err); 383*f0865ec9SKyle Evans MUST_HAVE((sig != NULL), ret, err); 384*f0865ec9SKyle Evans MUST_HAVE((curve_name != NULL), ret, err); 385*f0865ec9SKyle Evans MUST_HAVE((hdr != NULL), ret, err); 386*f0865ec9SKyle Evans #if (MAX_BUF_LEN <= 255) 387*f0865ec9SKyle Evans /* No need to check this is sizeof(buf) exceeds 256. 388*f0865ec9SKyle Evans * (avoids -Werror,-Wtautological-constant-out-of-range-compare) 389*f0865ec9SKyle Evans */ 390*f0865ec9SKyle Evans MUST_HAVE(EC_STRUCTURED_SIG_EXPORT_SIZE(siglen) <= sizeof(buf), ret, err); 391*f0865ec9SKyle Evans #endif 392*f0865ec9SKyle Evans /* Import the data from the input file */ 393*f0865ec9SKyle Evans in_file = fopen(in_fname, "rb"); 394*f0865ec9SKyle Evans if (in_file == NULL) { 395*f0865ec9SKyle Evans ret = -1; 396*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_fname); 397*f0865ec9SKyle Evans goto err; 398*f0865ec9SKyle Evans } 399*f0865ec9SKyle Evans out_file = fopen(out_fname, "wb"); 400*f0865ec9SKyle Evans if (out_file == NULL) { 401*f0865ec9SKyle Evans ret = -1; 402*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", out_fname); 403*f0865ec9SKyle Evans goto err; 404*f0865ec9SKyle Evans } 405*f0865ec9SKyle Evans if (hdr != NULL) { 406*f0865ec9SKyle Evans /* Write the metadata header as a prepending information */ 407*f0865ec9SKyle Evans written = fwrite(hdr, 1, sizeof(metadata_hdr), out_file); 408*f0865ec9SKyle Evans if (written != sizeof(metadata_hdr)) { 409*f0865ec9SKyle Evans ret = -1; 410*f0865ec9SKyle Evans goto err; 411*f0865ec9SKyle Evans } 412*f0865ec9SKyle Evans } 413*f0865ec9SKyle Evans 414*f0865ec9SKyle Evans while (1) { 415*f0865ec9SKyle Evans read = fread(buf, 1, sizeof(buf), in_file); 416*f0865ec9SKyle Evans written = fwrite(buf, 1, read, out_file); 417*f0865ec9SKyle Evans if (written != read) { 418*f0865ec9SKyle Evans ret = -1; 419*f0865ec9SKyle Evans printf("Error: error when writing to %s\n", 420*f0865ec9SKyle Evans out_fname); 421*f0865ec9SKyle Evans goto err; 422*f0865ec9SKyle Evans } 423*f0865ec9SKyle Evans if (read != sizeof(buf)) { 424*f0865ec9SKyle Evans if (feof(in_file)) { 425*f0865ec9SKyle Evans /* EOF */ 426*f0865ec9SKyle Evans break; 427*f0865ec9SKyle Evans } else { 428*f0865ec9SKyle Evans ret = -1; 429*f0865ec9SKyle Evans printf("Error: error when reading from %s\n", 430*f0865ec9SKyle Evans in_fname); 431*f0865ec9SKyle Evans goto err; 432*f0865ec9SKyle Evans } 433*f0865ec9SKyle Evans } 434*f0865ec9SKyle Evans 435*f0865ec9SKyle Evans } 436*f0865ec9SKyle Evans 437*f0865ec9SKyle Evans /* Compute the structured signature */ 438*f0865ec9SKyle Evans ret = ec_structured_sig_export_to_buf(sig, siglen, buf, sizeof(buf), 439*f0865ec9SKyle Evans sig_type, hash_type, curve_name); 440*f0865ec9SKyle Evans if (ret) { 441*f0865ec9SKyle Evans ret = -1; 442*f0865ec9SKyle Evans printf("Error: error when exporting signature to structured buffer\n"); 443*f0865ec9SKyle Evans goto err; 444*f0865ec9SKyle Evans } 445*f0865ec9SKyle Evans /* Store the signature buffer */ 446*f0865ec9SKyle Evans written = 447*f0865ec9SKyle Evans fwrite(buf, 1, EC_STRUCTURED_SIG_EXPORT_SIZE(siglen), 448*f0865ec9SKyle Evans out_file); 449*f0865ec9SKyle Evans if (written != EC_STRUCTURED_SIG_EXPORT_SIZE(siglen)) { 450*f0865ec9SKyle Evans ret = -1; 451*f0865ec9SKyle Evans printf("Error: error when writing to %s\n", out_fname); 452*f0865ec9SKyle Evans goto err; 453*f0865ec9SKyle Evans } 454*f0865ec9SKyle Evans 455*f0865ec9SKyle Evans ret = 0; 456*f0865ec9SKyle Evans 457*f0865ec9SKyle Evans err: 458*f0865ec9SKyle Evans if(in_file != NULL){ 459*f0865ec9SKyle Evans if(fclose(in_file)){ 460*f0865ec9SKyle Evans ret = -1; 461*f0865ec9SKyle Evans } 462*f0865ec9SKyle Evans } 463*f0865ec9SKyle Evans if(out_file != NULL){ 464*f0865ec9SKyle Evans if(fclose(out_file)){ 465*f0865ec9SKyle Evans ret = -1; 466*f0865ec9SKyle Evans } 467*f0865ec9SKyle Evans } 468*f0865ec9SKyle Evans return ret; 469*f0865ec9SKyle Evans } 470*f0865ec9SKyle Evans 471*f0865ec9SKyle Evans /* Get the raw size of a file */ 472*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int get_file_size(const char *in_fname, size_t *outsz) 473*f0865ec9SKyle Evans { 474*f0865ec9SKyle Evans FILE *in_file = NULL; 475*f0865ec9SKyle Evans long size; 476*f0865ec9SKyle Evans int ret; 477*f0865ec9SKyle Evans 478*f0865ec9SKyle Evans MUST_HAVE(outsz != NULL, ret, err); 479*f0865ec9SKyle Evans MUST_HAVE(in_fname != NULL, ret, err); 480*f0865ec9SKyle Evans 481*f0865ec9SKyle Evans *outsz = 0; 482*f0865ec9SKyle Evans 483*f0865ec9SKyle Evans in_file = fopen(in_fname, "rb"); 484*f0865ec9SKyle Evans if (in_file == NULL) { 485*f0865ec9SKyle Evans ret = -1; 486*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_fname); 487*f0865ec9SKyle Evans goto err; 488*f0865ec9SKyle Evans } 489*f0865ec9SKyle Evans /* Compute the size of the file */ 490*f0865ec9SKyle Evans if (fseek(in_file, 0L, SEEK_END)) { 491*f0865ec9SKyle Evans ret = -1; 492*f0865ec9SKyle Evans printf("Error: file %s cannot be seeked\n", in_fname); 493*f0865ec9SKyle Evans goto err; 494*f0865ec9SKyle Evans } 495*f0865ec9SKyle Evans size = ftell(in_file); 496*f0865ec9SKyle Evans if (size < 0) { 497*f0865ec9SKyle Evans ret = -1; 498*f0865ec9SKyle Evans printf("Error: cannot compute file %s size\n", in_fname); 499*f0865ec9SKyle Evans goto err; 500*f0865ec9SKyle Evans } 501*f0865ec9SKyle Evans /* Check overflow */ 502*f0865ec9SKyle Evans if ((u64)size > (u64)(0xffffffff)) { 503*f0865ec9SKyle Evans ret = -1; 504*f0865ec9SKyle Evans printf("Error: file %s size %ld overflow (>= 2^32)\n", 505*f0865ec9SKyle Evans in_fname, size); 506*f0865ec9SKyle Evans goto err; 507*f0865ec9SKyle Evans } 508*f0865ec9SKyle Evans 509*f0865ec9SKyle Evans *outsz = (u32)size; 510*f0865ec9SKyle Evans ret = 0; 511*f0865ec9SKyle Evans 512*f0865ec9SKyle Evans err: 513*f0865ec9SKyle Evans if(in_file != NULL){ 514*f0865ec9SKyle Evans if(fclose(in_file)){ 515*f0865ec9SKyle Evans ret = -1; 516*f0865ec9SKyle Evans } 517*f0865ec9SKyle Evans } 518*f0865ec9SKyle Evans return ret; 519*f0865ec9SKyle Evans } 520*f0865ec9SKyle Evans 521*f0865ec9SKyle Evans /* Generate a proper handler from a given type and other information */ 522*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int generate_metadata_hdr(metadata_hdr * hdr, const char *hdr_type, 523*f0865ec9SKyle Evans const char *version, size_t len, u8 siglen) 524*f0865ec9SKyle Evans { 525*f0865ec9SKyle Evans unsigned long ver; 526*f0865ec9SKyle Evans char *endptr; /* for strtoul() */ 527*f0865ec9SKyle Evans int ret, check; 528*f0865ec9SKyle Evans 529*f0865ec9SKyle Evans MUST_HAVE((hdr != NULL), ret, err); 530*f0865ec9SKyle Evans MUST_HAVE((hdr_type != NULL), ret, err); 531*f0865ec9SKyle Evans MUST_HAVE((version != NULL), ret, err); 532*f0865ec9SKyle Evans 533*f0865ec9SKyle Evans /* The magic value */ 534*f0865ec9SKyle Evans hdr->magic = HDR_MAGIC; 535*f0865ec9SKyle Evans 536*f0865ec9SKyle Evans /* The given version */ 537*f0865ec9SKyle Evans #ifdef WITH_STDLIB 538*f0865ec9SKyle Evans errno = 0; 539*f0865ec9SKyle Evans #endif 540*f0865ec9SKyle Evans ver = strtoul(version, &endptr, 0); 541*f0865ec9SKyle Evans #ifdef WITH_STDLIB 542*f0865ec9SKyle Evans if(errno){ 543*f0865ec9SKyle Evans ret = -1; 544*f0865ec9SKyle Evans printf("Error: error in strtoul\n"); 545*f0865ec9SKyle Evans goto err; 546*f0865ec9SKyle Evans } 547*f0865ec9SKyle Evans #endif 548*f0865ec9SKyle Evans if (*endptr != '\0') { 549*f0865ec9SKyle Evans ret = -1; 550*f0865ec9SKyle Evans printf("Error: error getting provided version %s\n", version); 551*f0865ec9SKyle Evans goto err; 552*f0865ec9SKyle Evans } 553*f0865ec9SKyle Evans if ((ver & 0xffffffff) != ver) { 554*f0865ec9SKyle Evans ret = -1; 555*f0865ec9SKyle Evans printf("Error: provided version %s is too long!\n", version); 556*f0865ec9SKyle Evans goto err; 557*f0865ec9SKyle Evans } 558*f0865ec9SKyle Evans hdr->version = (u32)ver; 559*f0865ec9SKyle Evans 560*f0865ec9SKyle Evans /* The image type */ 561*f0865ec9SKyle Evans hdr->type = IMAGE_TYPE_UNKNOWN; 562*f0865ec9SKyle Evans ret = are_str_equal(hdr_type, "IMAGE_TYPE0", &check); EG(ret, err); 563*f0865ec9SKyle Evans if (check) { 564*f0865ec9SKyle Evans hdr->type = IMAGE_TYPE0; 565*f0865ec9SKyle Evans } 566*f0865ec9SKyle Evans ret = are_str_equal(hdr_type, "IMAGE_TYPE1", &check); EG(ret, err); 567*f0865ec9SKyle Evans if (check) { 568*f0865ec9SKyle Evans hdr->type = IMAGE_TYPE1; 569*f0865ec9SKyle Evans } 570*f0865ec9SKyle Evans ret = are_str_equal(hdr_type, "IMAGE_TYPE2", &check); EG(ret, err); 571*f0865ec9SKyle Evans if (check) { 572*f0865ec9SKyle Evans hdr->type = IMAGE_TYPE2; 573*f0865ec9SKyle Evans } 574*f0865ec9SKyle Evans ret = are_str_equal(hdr_type, "IMAGE_TYPE3", &check); EG(ret, err); 575*f0865ec9SKyle Evans if (check) { 576*f0865ec9SKyle Evans hdr->type = IMAGE_TYPE3; 577*f0865ec9SKyle Evans } 578*f0865ec9SKyle Evans if (hdr->type == IMAGE_TYPE_UNKNOWN) { 579*f0865ec9SKyle Evans ret = -1; 580*f0865ec9SKyle Evans printf("Error: unknown header type %s\n", hdr_type); 581*f0865ec9SKyle Evans goto err; 582*f0865ec9SKyle Evans } 583*f0865ec9SKyle Evans 584*f0865ec9SKyle Evans /* The length without the signature */ 585*f0865ec9SKyle Evans if ((len & 0xffffffff) != len) { 586*f0865ec9SKyle Evans ret = -1; 587*f0865ec9SKyle Evans printf("Error: provided length value %lu is too long!\n", (unsigned long)len); 588*f0865ec9SKyle Evans goto err; 589*f0865ec9SKyle Evans } 590*f0865ec9SKyle Evans hdr->len = (u32)len; 591*f0865ec9SKyle Evans 592*f0865ec9SKyle Evans /* The signature length */ 593*f0865ec9SKyle Evans hdr->siglen = siglen; 594*f0865ec9SKyle Evans 595*f0865ec9SKyle Evans ret = 0; 596*f0865ec9SKyle Evans 597*f0865ec9SKyle Evans err: 598*f0865ec9SKyle Evans return ret; 599*f0865ec9SKyle Evans } 600*f0865ec9SKyle Evans 601*f0865ec9SKyle Evans /* Warn the user that the provided ancillary data won't be used 602*f0865ec9SKyle Evans * if the algorithm does not need them. 603*f0865ec9SKyle Evans */ 604*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int check_ancillary_data(const char *adata, ec_alg_type sig_type, const char *sig_name, int *check) 605*f0865ec9SKyle Evans { 606*f0865ec9SKyle Evans int ret; 607*f0865ec9SKyle Evans 608*f0865ec9SKyle Evans MUST_HAVE(check != NULL, ret, err); 609*f0865ec9SKyle Evans MUST_HAVE(adata != NULL, ret, err); 610*f0865ec9SKyle Evans MUST_HAVE(sig_name != NULL, ret, err); 611*f0865ec9SKyle Evans MUST_HAVE(sig_type != UNKNOWN_ALG, ret, err); 612*f0865ec9SKyle Evans 613*f0865ec9SKyle Evans (*check) = 0; 614*f0865ec9SKyle Evans 615*f0865ec9SKyle Evans #if defined(WITH_SIG_EDDSA25519) 616*f0865ec9SKyle Evans if(sig_type == EDDSA25519CTX){ 617*f0865ec9SKyle Evans (*check) = 1; 618*f0865ec9SKyle Evans } 619*f0865ec9SKyle Evans #endif 620*f0865ec9SKyle Evans #if defined(WITH_SIG_EDDSA448) 621*f0865ec9SKyle Evans if(sig_type == EDDSA448){ 622*f0865ec9SKyle Evans (*check) = 1; 623*f0865ec9SKyle Evans } 624*f0865ec9SKyle Evans #endif 625*f0865ec9SKyle Evans #if defined(WITH_SIG_SM2) 626*f0865ec9SKyle Evans if(sig_type == SM2){ 627*f0865ec9SKyle Evans (*check) = 1; 628*f0865ec9SKyle Evans } 629*f0865ec9SKyle Evans #endif 630*f0865ec9SKyle Evans if((*check) == 0){ 631*f0865ec9SKyle Evans printf("Warning: you have provided optional ancillary data "\ 632*f0865ec9SKyle Evans "with a signature algorithm %s that does not need it! "\ 633*f0865ec9SKyle Evans "This data is ignored.\n", sig_name); 634*f0865ec9SKyle Evans } 635*f0865ec9SKyle Evans 636*f0865ec9SKyle Evans ret = 0; 637*f0865ec9SKyle Evans 638*f0865ec9SKyle Evans err: 639*f0865ec9SKyle Evans return ret; 640*f0865ec9SKyle Evans } 641*f0865ec9SKyle Evans 642*f0865ec9SKyle Evans /* 643*f0865ec9SKyle Evans * Sign data from file and append signature 644*f0865ec9SKyle Evans */ 645*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int sign_bin_file(const char *ec_name, const char *ec_sig_name, 646*f0865ec9SKyle Evans const char *hash_algorithm, const char *in_fname, 647*f0865ec9SKyle Evans const char *in_key_fname, 648*f0865ec9SKyle Evans const char *out_fname, const char *hdr_type, 649*f0865ec9SKyle Evans const char *version, const char *adata, u16 adata_len) 650*f0865ec9SKyle Evans { 651*f0865ec9SKyle Evans u8 sig[EC_MAX_SIGLEN]; 652*f0865ec9SKyle Evans u8 buf[MAX_BUF_LEN]; 653*f0865ec9SKyle Evans u8 siglen; 654*f0865ec9SKyle Evans FILE *in_file = NULL; 655*f0865ec9SKyle Evans ec_key_pair key_pair; 656*f0865ec9SKyle Evans FILE *in_key_file = NULL; 657*f0865ec9SKyle Evans FILE *out_file = NULL; 658*f0865ec9SKyle Evans const ec_str_params *ec_str_p; 659*f0865ec9SKyle Evans ec_params params; 660*f0865ec9SKyle Evans int ret, check; 661*f0865ec9SKyle Evans ec_alg_type sig_type; 662*f0865ec9SKyle Evans hash_alg_type hash_type; 663*f0865ec9SKyle Evans u8 priv_key_buf[EC_STRUCTURED_PRIV_KEY_MAX_EXPORT_SIZE]; 664*f0865ec9SKyle Evans u8 priv_key_buf_len; 665*f0865ec9SKyle Evans size_t raw_data_len; 666*f0865ec9SKyle Evans metadata_hdr hdr; 667*f0865ec9SKyle Evans size_t read, to_read; 668*f0865ec9SKyle Evans int eof; 669*f0865ec9SKyle Evans u8 *allocated_buff = NULL; 670*f0865ec9SKyle Evans struct ec_sign_context sig_ctx; 671*f0865ec9SKyle Evans 672*f0865ec9SKyle Evans MUST_HAVE(ec_name != NULL, ret, err); 673*f0865ec9SKyle Evans MUST_HAVE(ec_sig_name != NULL, ret, err); 674*f0865ec9SKyle Evans MUST_HAVE(hash_algorithm != NULL, ret, err); 675*f0865ec9SKyle Evans MUST_HAVE(in_fname != NULL, ret, err); 676*f0865ec9SKyle Evans MUST_HAVE(in_key_fname != NULL, ret, err); 677*f0865ec9SKyle Evans MUST_HAVE(out_fname != NULL, ret, err); 678*f0865ec9SKyle Evans 679*f0865ec9SKyle Evans /************************************/ 680*f0865ec9SKyle Evans /* Get parameters from pretty names */ 681*f0865ec9SKyle Evans if (string_to_params 682*f0865ec9SKyle Evans (ec_name, ec_sig_name, &sig_type, &ec_str_p, hash_algorithm, 683*f0865ec9SKyle Evans &hash_type)) { 684*f0865ec9SKyle Evans ret = -1; 685*f0865ec9SKyle Evans goto err; 686*f0865ec9SKyle Evans } 687*f0865ec9SKyle Evans if(adata != NULL){ 688*f0865ec9SKyle Evans /* Check if ancillary data will be used */ 689*f0865ec9SKyle Evans ret = check_ancillary_data(adata, sig_type, ec_sig_name, &check); EG(ret, err); 690*f0865ec9SKyle Evans } 691*f0865ec9SKyle Evans /* Import the parameters */ 692*f0865ec9SKyle Evans ret = import_params(¶ms, ec_str_p); EG(ret, err); 693*f0865ec9SKyle Evans 694*f0865ec9SKyle Evans /************************************/ 695*f0865ec9SKyle Evans /* Import the private key from the file */ 696*f0865ec9SKyle Evans in_key_file = fopen(in_key_fname, "rb"); 697*f0865ec9SKyle Evans if (in_key_file == NULL) { 698*f0865ec9SKyle Evans ret = -1; 699*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_key_fname); 700*f0865ec9SKyle Evans goto err; 701*f0865ec9SKyle Evans } 702*f0865ec9SKyle Evans priv_key_buf_len = (u8)fread(priv_key_buf, 1, sizeof(priv_key_buf), 703*f0865ec9SKyle Evans in_key_file); 704*f0865ec9SKyle Evans ret = ec_structured_key_pair_import_from_priv_key_buf(&key_pair, 705*f0865ec9SKyle Evans ¶ms, 706*f0865ec9SKyle Evans priv_key_buf, 707*f0865ec9SKyle Evans priv_key_buf_len, 708*f0865ec9SKyle Evans sig_type); 709*f0865ec9SKyle Evans if (ret) { 710*f0865ec9SKyle Evans ret = -1; 711*f0865ec9SKyle Evans printf("Error: error when importing key pair from %s\n", 712*f0865ec9SKyle Evans in_key_fname); 713*f0865ec9SKyle Evans goto err; 714*f0865ec9SKyle Evans } 715*f0865ec9SKyle Evans 716*f0865ec9SKyle Evans ret = get_file_size(in_fname, &raw_data_len); 717*f0865ec9SKyle Evans if (ret) { 718*f0865ec9SKyle Evans ret = -1; 719*f0865ec9SKyle Evans printf("Error: cannot retrieve file %s size\n", in_fname); 720*f0865ec9SKyle Evans goto err; 721*f0865ec9SKyle Evans } 722*f0865ec9SKyle Evans if(raw_data_len == 0){ 723*f0865ec9SKyle Evans ret = -1; 724*f0865ec9SKyle Evans printf("Error: file %s seems to be empty!\n", in_fname); 725*f0865ec9SKyle Evans goto err; 726*f0865ec9SKyle Evans } 727*f0865ec9SKyle Evans ret = ec_get_sig_len(¶ms, sig_type, hash_type, &siglen); 728*f0865ec9SKyle Evans if (ret) { 729*f0865ec9SKyle Evans ret = -1; 730*f0865ec9SKyle Evans printf("Error getting effective signature length from %s\n", 731*f0865ec9SKyle Evans (const char *)(ec_str_p->name->buf)); 732*f0865ec9SKyle Evans goto err; 733*f0865ec9SKyle Evans } 734*f0865ec9SKyle Evans 735*f0865ec9SKyle Evans /* Structured export case, we forge a header */ 736*f0865ec9SKyle Evans if((hdr_type != NULL) && (version != NULL)){ 737*f0865ec9SKyle Evans /************************************/ 738*f0865ec9SKyle Evans /* Forge the header */ 739*f0865ec9SKyle Evans ret = generate_metadata_hdr(&hdr, hdr_type, version, raw_data_len, 740*f0865ec9SKyle Evans EC_STRUCTURED_SIG_EXPORT_SIZE(siglen)); 741*f0865ec9SKyle Evans 742*f0865ec9SKyle Evans if (ret) { 743*f0865ec9SKyle Evans ret = -1; 744*f0865ec9SKyle Evans printf("Error: error when generating metadata\n"); 745*f0865ec9SKyle Evans goto err; 746*f0865ec9SKyle Evans } 747*f0865ec9SKyle Evans } 748*f0865ec9SKyle Evans 749*f0865ec9SKyle Evans /* Check if we support streaming */ 750*f0865ec9SKyle Evans ret = is_sign_streaming_mode_supported(sig_type, &check); EG(ret, err); 751*f0865ec9SKyle Evans if(check){ 752*f0865ec9SKyle Evans /**** We support streaming mode ****/ 753*f0865ec9SKyle Evans /* 754*f0865ec9SKyle Evans * Initialize signature context and start signature computation 755*f0865ec9SKyle Evans * with generated metadata header. 756*f0865ec9SKyle Evans */ 757*f0865ec9SKyle Evans ret = ec_sign_init(&sig_ctx, &key_pair, sig_type, hash_type, (const u8*)adata, adata_len); 758*f0865ec9SKyle Evans if (ret) { 759*f0865ec9SKyle Evans ret = -1; 760*f0865ec9SKyle Evans printf("Error: error when signing\n"); 761*f0865ec9SKyle Evans goto err; 762*f0865ec9SKyle Evans } 763*f0865ec9SKyle Evans 764*f0865ec9SKyle Evans /* Structured export case, we prepend the header in the signature */ 765*f0865ec9SKyle Evans if((hdr_type != NULL) && (version != NULL)){ 766*f0865ec9SKyle Evans ret = ec_sign_update(&sig_ctx, (const u8 *)&hdr, sizeof(metadata_hdr)); 767*f0865ec9SKyle Evans if (ret) { 768*f0865ec9SKyle Evans ret = -1; 769*f0865ec9SKyle Evans printf("Error: error when signing\n"); 770*f0865ec9SKyle Evans goto err; 771*f0865ec9SKyle Evans } 772*f0865ec9SKyle Evans } 773*f0865ec9SKyle Evans 774*f0865ec9SKyle Evans /* 775*f0865ec9SKyle Evans * Read file content chunk by chunk up to file length, passing each 776*f0865ec9SKyle Evans * chunk to signature update function 777*f0865ec9SKyle Evans */ 778*f0865ec9SKyle Evans in_file = fopen(in_fname, "rb"); 779*f0865ec9SKyle Evans if (in_file == NULL) { 780*f0865ec9SKyle Evans ret = -1; 781*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_fname); 782*f0865ec9SKyle Evans goto err; 783*f0865ec9SKyle Evans } 784*f0865ec9SKyle Evans 785*f0865ec9SKyle Evans eof = 0; 786*f0865ec9SKyle Evans clearerr(in_file); 787*f0865ec9SKyle Evans while (raw_data_len && !eof) { 788*f0865ec9SKyle Evans to_read = 789*f0865ec9SKyle Evans (raw_data_len < 790*f0865ec9SKyle Evans sizeof(buf)) ? raw_data_len : sizeof(buf); 791*f0865ec9SKyle Evans memset(buf, 0, sizeof(buf)); 792*f0865ec9SKyle Evans read = fread(buf, 1, to_read, in_file); 793*f0865ec9SKyle Evans if (read != to_read) { 794*f0865ec9SKyle Evans /* Check if this was EOF */ 795*f0865ec9SKyle Evans ret = feof(in_file); 796*f0865ec9SKyle Evans clearerr(in_file); 797*f0865ec9SKyle Evans if (ret) { 798*f0865ec9SKyle Evans eof = 1; 799*f0865ec9SKyle Evans } 800*f0865ec9SKyle Evans } 801*f0865ec9SKyle Evans 802*f0865ec9SKyle Evans if (read > raw_data_len) { 803*f0865ec9SKyle Evans /* we read more than expected: leave! */ 804*f0865ec9SKyle Evans break; 805*f0865ec9SKyle Evans } 806*f0865ec9SKyle Evans 807*f0865ec9SKyle Evans raw_data_len -= read; 808*f0865ec9SKyle Evans 809*f0865ec9SKyle Evans ret = ec_sign_update(&sig_ctx, buf, (u32)read); 810*f0865ec9SKyle Evans if (ret) { 811*f0865ec9SKyle Evans break; 812*f0865ec9SKyle Evans } 813*f0865ec9SKyle Evans } 814*f0865ec9SKyle Evans 815*f0865ec9SKyle Evans if (raw_data_len) { 816*f0865ec9SKyle Evans ret = -1; 817*f0865ec9SKyle Evans printf("Error: unable to read full file content\n"); 818*f0865ec9SKyle Evans goto err; 819*f0865ec9SKyle Evans } 820*f0865ec9SKyle Evans 821*f0865ec9SKyle Evans /* We can now complete signature generation */ 822*f0865ec9SKyle Evans ret = ec_sign_finalize(&sig_ctx, sig, siglen); 823*f0865ec9SKyle Evans if (ret) { 824*f0865ec9SKyle Evans ret = -1; 825*f0865ec9SKyle Evans printf("Error: error when signing\n"); 826*f0865ec9SKyle Evans goto err; 827*f0865ec9SKyle Evans } 828*f0865ec9SKyle Evans } 829*f0865ec9SKyle Evans else{ 830*f0865ec9SKyle Evans /**** We do not support streaming mode ****/ 831*f0865ec9SKyle Evans /* Since we don't support streaming mode, we unfortunately have to 832*f0865ec9SKyle Evans * use a dynamic allocation here. 833*f0865ec9SKyle Evans */ 834*f0865ec9SKyle Evans size_t offset = 0; 835*f0865ec9SKyle Evans allocated_buff = (u8*)malloc(1); 836*f0865ec9SKyle Evans if(allocated_buff == NULL){ 837*f0865ec9SKyle Evans ret = -1; 838*f0865ec9SKyle Evans printf("Error: allocation error\n"); 839*f0865ec9SKyle Evans goto err; 840*f0865ec9SKyle Evans } 841*f0865ec9SKyle Evans if((hdr_type != NULL) && (version != NULL)){ 842*f0865ec9SKyle Evans allocated_buff = (u8*)realloc(allocated_buff, sizeof(hdr)); 843*f0865ec9SKyle Evans if(allocated_buff == NULL){ 844*f0865ec9SKyle Evans ret = -1; 845*f0865ec9SKyle Evans printf("Error: allocation error\n"); 846*f0865ec9SKyle Evans goto err; 847*f0865ec9SKyle Evans } 848*f0865ec9SKyle Evans memcpy(allocated_buff, &hdr, sizeof(hdr)); 849*f0865ec9SKyle Evans offset += sizeof(hdr); 850*f0865ec9SKyle Evans } 851*f0865ec9SKyle Evans in_file = fopen(in_fname, "rb"); 852*f0865ec9SKyle Evans if (in_file == NULL) { 853*f0865ec9SKyle Evans ret = -1; 854*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_fname); 855*f0865ec9SKyle Evans goto err; 856*f0865ec9SKyle Evans } 857*f0865ec9SKyle Evans 858*f0865ec9SKyle Evans eof = 0; 859*f0865ec9SKyle Evans clearerr(in_file); 860*f0865ec9SKyle Evans while (raw_data_len && !eof) { 861*f0865ec9SKyle Evans to_read = 862*f0865ec9SKyle Evans (raw_data_len < 863*f0865ec9SKyle Evans sizeof(buf)) ? raw_data_len : sizeof(buf); 864*f0865ec9SKyle Evans read = fread(buf, 1, to_read, in_file); 865*f0865ec9SKyle Evans if (read != to_read) { 866*f0865ec9SKyle Evans /* Check if this was EOF */ 867*f0865ec9SKyle Evans ret = feof(in_file); 868*f0865ec9SKyle Evans clearerr(in_file); 869*f0865ec9SKyle Evans if (ret) { 870*f0865ec9SKyle Evans eof = 1; 871*f0865ec9SKyle Evans } 872*f0865ec9SKyle Evans } 873*f0865ec9SKyle Evans 874*f0865ec9SKyle Evans if (read > raw_data_len) { 875*f0865ec9SKyle Evans /* we read more than expected: leave! */ 876*f0865ec9SKyle Evans break; 877*f0865ec9SKyle Evans } 878*f0865ec9SKyle Evans 879*f0865ec9SKyle Evans raw_data_len -= read; 880*f0865ec9SKyle Evans 881*f0865ec9SKyle Evans allocated_buff = (u8*)realloc(allocated_buff, offset + read); 882*f0865ec9SKyle Evans if(allocated_buff == NULL){ 883*f0865ec9SKyle Evans ret = -1; 884*f0865ec9SKyle Evans printf("Error: allocation error\n"); 885*f0865ec9SKyle Evans goto err; 886*f0865ec9SKyle Evans } 887*f0865ec9SKyle Evans memcpy(allocated_buff + offset, buf, read); 888*f0865ec9SKyle Evans offset += read; 889*f0865ec9SKyle Evans } 890*f0865ec9SKyle Evans 891*f0865ec9SKyle Evans if (raw_data_len) { 892*f0865ec9SKyle Evans ret = -1; 893*f0865ec9SKyle Evans printf("Error: unable to read full file content\n"); 894*f0865ec9SKyle Evans goto err; 895*f0865ec9SKyle Evans } 896*f0865ec9SKyle Evans 897*f0865ec9SKyle Evans /* Sign */ 898*f0865ec9SKyle Evans ret = ec_sign(sig, siglen, &key_pair, allocated_buff, (u32)offset, sig_type, hash_type, (const u8*)adata, adata_len); 899*f0865ec9SKyle Evans if(ret){ 900*f0865ec9SKyle Evans ret = -1; 901*f0865ec9SKyle Evans printf("Error: error when signing\n"); 902*f0865ec9SKyle Evans goto err; 903*f0865ec9SKyle Evans } 904*f0865ec9SKyle Evans } 905*f0865ec9SKyle Evans 906*f0865ec9SKyle Evans /* Structured export case, forge the full structured file 907*f0865ec9SKyle Evans * with HEADER || raw_binary || signature 908*f0865ec9SKyle Evans */ 909*f0865ec9SKyle Evans if((hdr_type != NULL) && (version != NULL)){ 910*f0865ec9SKyle Evans /***********************************/ 911*f0865ec9SKyle Evans /* Store the header, the raw data of the file as well as the signature */ 912*f0865ec9SKyle Evans ret = store_sig(in_fname, out_fname, sig, siglen, sig_type, 913*f0865ec9SKyle Evans hash_type, params.curve_name, &hdr); 914*f0865ec9SKyle Evans if (ret) { 915*f0865ec9SKyle Evans ret = -1; 916*f0865ec9SKyle Evans printf("Error: error when storing signature to %s\n", 917*f0865ec9SKyle Evans out_fname); 918*f0865ec9SKyle Evans goto err; 919*f0865ec9SKyle Evans } 920*f0865ec9SKyle Evans } 921*f0865ec9SKyle Evans else{ 922*f0865ec9SKyle Evans /* Store the raw binary signature in the output file */ 923*f0865ec9SKyle Evans size_t written; 924*f0865ec9SKyle Evans 925*f0865ec9SKyle Evans out_file = fopen(out_fname, "wb"); 926*f0865ec9SKyle Evans if (out_file == NULL) { 927*f0865ec9SKyle Evans ret = -1; 928*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", out_fname); 929*f0865ec9SKyle Evans goto err; 930*f0865ec9SKyle Evans } 931*f0865ec9SKyle Evans written = fwrite(sig, 1, siglen, out_file); 932*f0865ec9SKyle Evans if (written != siglen) { 933*f0865ec9SKyle Evans ret = -1; 934*f0865ec9SKyle Evans printf("Error: error when writing to %s\n", 935*f0865ec9SKyle Evans out_fname); 936*f0865ec9SKyle Evans goto err; 937*f0865ec9SKyle Evans } 938*f0865ec9SKyle Evans } 939*f0865ec9SKyle Evans 940*f0865ec9SKyle Evans ret = 0; 941*f0865ec9SKyle Evans 942*f0865ec9SKyle Evans err: 943*f0865ec9SKyle Evans if(in_file != NULL){ 944*f0865ec9SKyle Evans if(fclose(in_file)){ 945*f0865ec9SKyle Evans ret = -1; 946*f0865ec9SKyle Evans } 947*f0865ec9SKyle Evans } 948*f0865ec9SKyle Evans if(in_key_file != NULL){ 949*f0865ec9SKyle Evans if(fclose(in_key_file)){ 950*f0865ec9SKyle Evans ret = -1; 951*f0865ec9SKyle Evans } 952*f0865ec9SKyle Evans } 953*f0865ec9SKyle Evans if(out_file != NULL){ 954*f0865ec9SKyle Evans if(fclose(out_file)){ 955*f0865ec9SKyle Evans ret = -1; 956*f0865ec9SKyle Evans } 957*f0865ec9SKyle Evans } 958*f0865ec9SKyle Evans if(allocated_buff != NULL){ 959*f0865ec9SKyle Evans free(allocated_buff); 960*f0865ec9SKyle Evans } 961*f0865ec9SKyle Evans return ret; 962*f0865ec9SKyle Evans } 963*f0865ec9SKyle Evans 964*f0865ec9SKyle Evans /* Dump metadata header */ 965*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int dump_hdr_info(const metadata_hdr * hdr) 966*f0865ec9SKyle Evans { 967*f0865ec9SKyle Evans int ret; 968*f0865ec9SKyle Evans 969*f0865ec9SKyle Evans if (hdr == NULL) { 970*f0865ec9SKyle Evans printf("Metadata header pointer is NULL!\n"); 971*f0865ec9SKyle Evans ret = -1; 972*f0865ec9SKyle Evans goto err; 973*f0865ec9SKyle Evans } 974*f0865ec9SKyle Evans 975*f0865ec9SKyle Evans /* Dump the header */ 976*f0865ec9SKyle Evans printf("Metadata header info:\n"); 977*f0865ec9SKyle Evans printf(" magic = 0x%08" PRIx32 "\n", hdr->magic); 978*f0865ec9SKyle Evans switch (hdr->type) { 979*f0865ec9SKyle Evans case IMAGE_TYPE0: 980*f0865ec9SKyle Evans printf(" type = IMAGE_TYPE0\n"); 981*f0865ec9SKyle Evans break; 982*f0865ec9SKyle Evans case IMAGE_TYPE1: 983*f0865ec9SKyle Evans printf(" type = IMAGE_TYPE1\n"); 984*f0865ec9SKyle Evans break; 985*f0865ec9SKyle Evans case IMAGE_TYPE2: 986*f0865ec9SKyle Evans printf(" type = IMAGE_TYPE2\n"); 987*f0865ec9SKyle Evans break; 988*f0865ec9SKyle Evans case IMAGE_TYPE3: 989*f0865ec9SKyle Evans printf(" type = IMAGE_TYPE3\n"); 990*f0865ec9SKyle Evans break; 991*f0865ec9SKyle Evans default: 992*f0865ec9SKyle Evans printf(" type %" PRIu32 " unknown!\n", hdr->type); 993*f0865ec9SKyle Evans break; 994*f0865ec9SKyle Evans } 995*f0865ec9SKyle Evans printf(" version = 0x%08" PRIx32 "\n", hdr->version); 996*f0865ec9SKyle Evans printf(" len = 0x%08" PRIx32 "\n", hdr->len); 997*f0865ec9SKyle Evans printf(" siglen = 0x%08" PRIx32 "\n", hdr->siglen); 998*f0865ec9SKyle Evans ret = 0; 999*f0865ec9SKyle Evans 1000*f0865ec9SKyle Evans err: 1001*f0865ec9SKyle Evans return ret; 1002*f0865ec9SKyle Evans } 1003*f0865ec9SKyle Evans 1004*f0865ec9SKyle Evans /* 1005*f0865ec9SKyle Evans * Verify signature data from file with appended signature 1006*f0865ec9SKyle Evans */ 1007*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int verify_bin_file(const char *ec_name, const char *ec_sig_name, 1008*f0865ec9SKyle Evans const char *hash_algorithm, 1009*f0865ec9SKyle Evans const char *in_fname, 1010*f0865ec9SKyle Evans const char *in_key_fname, const char *in_sig_fname, const char *adata, u16 adata_len) 1011*f0865ec9SKyle Evans { 1012*f0865ec9SKyle Evans u8 st_sig[EC_STRUCTURED_SIG_EXPORT_SIZE(EC_MAX_SIGLEN)]; 1013*f0865ec9SKyle Evans u8 stored_curve_name[MAX_CURVE_NAME_LEN]; 1014*f0865ec9SKyle Evans u8 pub_key_buf[EC_STRUCTURED_PUB_KEY_MAX_EXPORT_SIZE]; 1015*f0865ec9SKyle Evans struct ec_verify_context verif_ctx; 1016*f0865ec9SKyle Evans ec_alg_type stored_sig_type; 1017*f0865ec9SKyle Evans hash_alg_type stored_hash_type; 1018*f0865ec9SKyle Evans const ec_str_params *ec_str_p; 1019*f0865ec9SKyle Evans ec_alg_type sig_type; 1020*f0865ec9SKyle Evans hash_alg_type hash_type; 1021*f0865ec9SKyle Evans u8 sig[EC_MAX_SIGLEN]; 1022*f0865ec9SKyle Evans u8 siglen, st_siglen; 1023*f0865ec9SKyle Evans size_t read, to_read; 1024*f0865ec9SKyle Evans u8 buf[MAX_BUF_LEN]; 1025*f0865ec9SKyle Evans u8 pub_key_buf_len; 1026*f0865ec9SKyle Evans size_t raw_data_len; 1027*f0865ec9SKyle Evans ec_pub_key pub_key; 1028*f0865ec9SKyle Evans FILE *in_key_file = NULL; 1029*f0865ec9SKyle Evans FILE *in_sig_file = NULL; 1030*f0865ec9SKyle Evans ec_params params; 1031*f0865ec9SKyle Evans metadata_hdr hdr; 1032*f0865ec9SKyle Evans size_t exp_len; 1033*f0865ec9SKyle Evans FILE *in_file = NULL; 1034*f0865ec9SKyle Evans int ret, eof, check; 1035*f0865ec9SKyle Evans u8 *allocated_buff = NULL; 1036*f0865ec9SKyle Evans 1037*f0865ec9SKyle Evans MUST_HAVE(ec_name != NULL, ret, err); 1038*f0865ec9SKyle Evans MUST_HAVE(ec_sig_name != NULL, ret, err); 1039*f0865ec9SKyle Evans MUST_HAVE(hash_algorithm != NULL, ret, err); 1040*f0865ec9SKyle Evans MUST_HAVE(in_fname != NULL, ret, err); 1041*f0865ec9SKyle Evans MUST_HAVE(in_key_fname != NULL, ret, err); 1042*f0865ec9SKyle Evans 1043*f0865ec9SKyle Evans /************************************/ 1044*f0865ec9SKyle Evans /* Get parameters from pretty names */ 1045*f0865ec9SKyle Evans ret = string_to_params(ec_name, ec_sig_name, &sig_type, &ec_str_p, 1046*f0865ec9SKyle Evans hash_algorithm, &hash_type); EG(ret, err); 1047*f0865ec9SKyle Evans if(adata != NULL){ 1048*f0865ec9SKyle Evans /* Check if ancillary data will be used */ 1049*f0865ec9SKyle Evans ret = check_ancillary_data(adata, sig_type, ec_sig_name, &check); EG(ret, err); 1050*f0865ec9SKyle Evans } 1051*f0865ec9SKyle Evans /* Import the parameters */ 1052*f0865ec9SKyle Evans ret = import_params(¶ms, ec_str_p); EG(ret, err); 1053*f0865ec9SKyle Evans 1054*f0865ec9SKyle Evans ret = ec_get_sig_len(¶ms, sig_type, hash_type, &siglen); 1055*f0865ec9SKyle Evans if (ret) { 1056*f0865ec9SKyle Evans ret = -1; 1057*f0865ec9SKyle Evans printf("Error getting effective signature length from %s\n", 1058*f0865ec9SKyle Evans (const char *)(ec_str_p->name->buf)); 1059*f0865ec9SKyle Evans goto err; 1060*f0865ec9SKyle Evans } 1061*f0865ec9SKyle Evans 1062*f0865ec9SKyle Evans /************************************/ 1063*f0865ec9SKyle Evans /* Import the public key from the file */ 1064*f0865ec9SKyle Evans in_key_file = fopen(in_key_fname, "rb"); 1065*f0865ec9SKyle Evans if (in_key_file == NULL) { 1066*f0865ec9SKyle Evans ret = -1; 1067*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_key_fname); 1068*f0865ec9SKyle Evans goto err; 1069*f0865ec9SKyle Evans } 1070*f0865ec9SKyle Evans pub_key_buf_len =(u8)fread(pub_key_buf, 1, sizeof(pub_key_buf), 1071*f0865ec9SKyle Evans in_key_file); 1072*f0865ec9SKyle Evans ret = ec_structured_pub_key_import_from_buf(&pub_key, ¶ms, 1073*f0865ec9SKyle Evans pub_key_buf, 1074*f0865ec9SKyle Evans pub_key_buf_len, sig_type); 1075*f0865ec9SKyle Evans if (ret) { 1076*f0865ec9SKyle Evans ret = -1; 1077*f0865ec9SKyle Evans printf("Error: error when importing public key from %s\n", 1078*f0865ec9SKyle Evans in_key_fname); 1079*f0865ec9SKyle Evans goto err; 1080*f0865ec9SKyle Evans } 1081*f0865ec9SKyle Evans 1082*f0865ec9SKyle Evans /* Let's first get file size */ 1083*f0865ec9SKyle Evans ret = get_file_size(in_fname, &raw_data_len); 1084*f0865ec9SKyle Evans if (ret) { 1085*f0865ec9SKyle Evans ret = -1; 1086*f0865ec9SKyle Evans printf("Error: cannot retrieve file %s size\n", in_fname); 1087*f0865ec9SKyle Evans goto err; 1088*f0865ec9SKyle Evans } 1089*f0865ec9SKyle Evans if(raw_data_len == 0){ 1090*f0865ec9SKyle Evans ret = -1; 1091*f0865ec9SKyle Evans printf("Error: file %s seems to be empty!\n", in_fname); 1092*f0865ec9SKyle Evans goto err; 1093*f0865ec9SKyle Evans } 1094*f0865ec9SKyle Evans 1095*f0865ec9SKyle Evans /* Open main file to verify ... */ 1096*f0865ec9SKyle Evans in_file = fopen(in_fname, "rb"); 1097*f0865ec9SKyle Evans if (in_file == NULL) { 1098*f0865ec9SKyle Evans ret = -1; 1099*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", in_fname); 1100*f0865ec9SKyle Evans goto err; 1101*f0865ec9SKyle Evans } 1102*f0865ec9SKyle Evans 1103*f0865ec9SKyle Evans /* 1104*f0865ec9SKyle Evans * We are in 'structured' mode, read the header and get the information 1105*f0865ec9SKyle Evans * from it 1106*f0865ec9SKyle Evans */ 1107*f0865ec9SKyle Evans if (in_sig_fname == NULL) { 1108*f0865ec9SKyle Evans /* ... and first read metadata header */ 1109*f0865ec9SKyle Evans read = fread(&hdr, 1, sizeof(hdr), in_file); 1110*f0865ec9SKyle Evans if (read != sizeof(hdr)) { 1111*f0865ec9SKyle Evans ret = -1; 1112*f0865ec9SKyle Evans printf("Error: unable to read metadata header " 1113*f0865ec9SKyle Evans "from file\n"); 1114*f0865ec9SKyle Evans goto err; 1115*f0865ec9SKyle Evans } 1116*f0865ec9SKyle Evans 1117*f0865ec9SKyle Evans /* Sanity checks on the header we get */ 1118*f0865ec9SKyle Evans if (hdr.magic != HDR_MAGIC) { 1119*f0865ec9SKyle Evans ret = -1; 1120*f0865ec9SKyle Evans printf("Error: got magic 0x%08" PRIx32 " instead of 0x%08x " 1121*f0865ec9SKyle Evans "from metadata header\n", hdr.magic, (unsigned int)HDR_MAGIC); 1122*f0865ec9SKyle Evans goto err; 1123*f0865ec9SKyle Evans } 1124*f0865ec9SKyle Evans 1125*f0865ec9SKyle Evans st_siglen = EC_STRUCTURED_SIG_EXPORT_SIZE(siglen); 1126*f0865ec9SKyle Evans MUST_HAVE(raw_data_len > (sizeof(hdr) + st_siglen), ret, err); 1127*f0865ec9SKyle Evans exp_len = raw_data_len - sizeof(hdr) - st_siglen; 1128*f0865ec9SKyle Evans if (hdr.len != exp_len) { 1129*f0865ec9SKyle Evans ret = -1; 1130*f0865ec9SKyle Evans printf("Error: got raw size of %" PRIu32 " instead of %lu from " 1131*f0865ec9SKyle Evans "metadata header\n", hdr.len, 1132*f0865ec9SKyle Evans (unsigned long)exp_len); 1133*f0865ec9SKyle Evans goto err; 1134*f0865ec9SKyle Evans } 1135*f0865ec9SKyle Evans 1136*f0865ec9SKyle Evans if (hdr.siglen != st_siglen) { 1137*f0865ec9SKyle Evans ret = -1; 1138*f0865ec9SKyle Evans printf("Error: got siglen %" PRIu32 " instead of %d from " 1139*f0865ec9SKyle Evans "metadata header\n", hdr.siglen, siglen); 1140*f0865ec9SKyle Evans goto err; 1141*f0865ec9SKyle Evans } 1142*f0865ec9SKyle Evans 1143*f0865ec9SKyle Evans /* Dump the header */ 1144*f0865ec9SKyle Evans ret = dump_hdr_info(&hdr); EG(ret, err); 1145*f0865ec9SKyle Evans 1146*f0865ec9SKyle Evans /* 1147*f0865ec9SKyle Evans * We now need to seek in file to get structured signature. 1148*f0865ec9SKyle Evans * Before doing that, let's first check size is large enough. 1149*f0865ec9SKyle Evans */ 1150*f0865ec9SKyle Evans if (raw_data_len < (sizeof(hdr) + st_siglen)) { 1151*f0865ec9SKyle Evans ret = -1; 1152*f0865ec9SKyle Evans goto err; 1153*f0865ec9SKyle Evans } 1154*f0865ec9SKyle Evans 1155*f0865ec9SKyle Evans ret = fseek(in_file, (long)(raw_data_len - st_siglen), 1156*f0865ec9SKyle Evans SEEK_SET); 1157*f0865ec9SKyle Evans if (ret) { 1158*f0865ec9SKyle Evans ret = -1; 1159*f0865ec9SKyle Evans printf("Error: file %s cannot be seeked\n", in_fname); 1160*f0865ec9SKyle Evans goto err; 1161*f0865ec9SKyle Evans } 1162*f0865ec9SKyle Evans read = fread(st_sig, 1, st_siglen, in_file); 1163*f0865ec9SKyle Evans if (read != st_siglen) { 1164*f0865ec9SKyle Evans ret = -1; 1165*f0865ec9SKyle Evans printf("Error: unable to read structure sig from " 1166*f0865ec9SKyle Evans "file\n"); 1167*f0865ec9SKyle Evans goto err; 1168*f0865ec9SKyle Evans } 1169*f0865ec9SKyle Evans /* Import the signature from the structured signature buffer */ 1170*f0865ec9SKyle Evans ret = ec_structured_sig_import_from_buf(sig, siglen, 1171*f0865ec9SKyle Evans st_sig, st_siglen, 1172*f0865ec9SKyle Evans &stored_sig_type, 1173*f0865ec9SKyle Evans &stored_hash_type, 1174*f0865ec9SKyle Evans stored_curve_name); 1175*f0865ec9SKyle Evans if (ret) { 1176*f0865ec9SKyle Evans ret = -1; 1177*f0865ec9SKyle Evans printf("Error: error when importing signature " 1178*f0865ec9SKyle Evans "from %s\n", in_fname); 1179*f0865ec9SKyle Evans goto err; 1180*f0865ec9SKyle Evans } 1181*f0865ec9SKyle Evans if (stored_sig_type != sig_type) { 1182*f0865ec9SKyle Evans ret = -1; 1183*f0865ec9SKyle Evans printf("Error: signature type imported from signature " 1184*f0865ec9SKyle Evans "mismatches with %s\n", ec_sig_name); 1185*f0865ec9SKyle Evans goto err; 1186*f0865ec9SKyle Evans } 1187*f0865ec9SKyle Evans if (stored_hash_type != hash_type) { 1188*f0865ec9SKyle Evans ret = -1; 1189*f0865ec9SKyle Evans printf("Error: hash algorithm type imported from " 1190*f0865ec9SKyle Evans "signature mismatches with %s\n", 1191*f0865ec9SKyle Evans hash_algorithm); 1192*f0865ec9SKyle Evans goto err; 1193*f0865ec9SKyle Evans } 1194*f0865ec9SKyle Evans ret = are_str_equal((char *)stored_curve_name, (char *)params.curve_name, &check); EG(ret, err); 1195*f0865ec9SKyle Evans if (!check) { 1196*f0865ec9SKyle Evans ret = -1; 1197*f0865ec9SKyle Evans printf("Error: curve type '%s' imported from signature " 1198*f0865ec9SKyle Evans "mismatches with '%s'\n", stored_curve_name, 1199*f0865ec9SKyle Evans params.curve_name); 1200*f0865ec9SKyle Evans goto err; 1201*f0865ec9SKyle Evans } 1202*f0865ec9SKyle Evans 1203*f0865ec9SKyle Evans /* 1204*f0865ec9SKyle Evans * Get back to the beginning of file, at the beginning of header 1205*f0865ec9SKyle Evans */ 1206*f0865ec9SKyle Evans if (fseek(in_file, 0, SEEK_SET)) { 1207*f0865ec9SKyle Evans ret = -1; 1208*f0865ec9SKyle Evans printf("Error: file %s cannot be seeked\n", in_fname); 1209*f0865ec9SKyle Evans goto err; 1210*f0865ec9SKyle Evans } 1211*f0865ec9SKyle Evans exp_len += sizeof(hdr); 1212*f0865ec9SKyle Evans } else { 1213*f0865ec9SKyle Evans /* Get the signature size */ 1214*f0865ec9SKyle Evans ret = get_file_size(in_sig_fname, &to_read); 1215*f0865ec9SKyle Evans if (ret) { 1216*f0865ec9SKyle Evans ret = -1; 1217*f0865ec9SKyle Evans printf("Error: cannot retrieve file %s size\n", 1218*f0865ec9SKyle Evans in_sig_fname); 1219*f0865ec9SKyle Evans goto err; 1220*f0865ec9SKyle Evans } 1221*f0865ec9SKyle Evans if((to_read > EC_MAX_SIGLEN) || (to_read > 255) || (to_read == 0)){ 1222*f0865ec9SKyle Evans /* This is not an expected size, get out */ 1223*f0865ec9SKyle Evans ret = -1; 1224*f0865ec9SKyle Evans printf("Error: size %d of signature in %s is > max " 1225*f0865ec9SKyle Evans "signature size %d or > 255", 1226*f0865ec9SKyle Evans (int)to_read, in_sig_fname, EC_MAX_SIGLEN); 1227*f0865ec9SKyle Evans goto err; 1228*f0865ec9SKyle Evans } 1229*f0865ec9SKyle Evans siglen = (u8)to_read; 1230*f0865ec9SKyle Evans /* Read the raw signature from the signature file */ 1231*f0865ec9SKyle Evans in_sig_file = fopen(in_sig_fname, "rb"); 1232*f0865ec9SKyle Evans if (in_sig_file == NULL) { 1233*f0865ec9SKyle Evans ret = -1; 1234*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", 1235*f0865ec9SKyle Evans in_sig_fname); 1236*f0865ec9SKyle Evans goto err; 1237*f0865ec9SKyle Evans } 1238*f0865ec9SKyle Evans read = fread(&sig, 1, siglen, in_sig_file); 1239*f0865ec9SKyle Evans if (read != siglen) { 1240*f0865ec9SKyle Evans ret = -1; 1241*f0865ec9SKyle Evans printf("Error: unable to read signature from %s\n", 1242*f0865ec9SKyle Evans in_sig_fname); 1243*f0865ec9SKyle Evans goto err; 1244*f0865ec9SKyle Evans } 1245*f0865ec9SKyle Evans exp_len = raw_data_len; 1246*f0865ec9SKyle Evans } 1247*f0865ec9SKyle Evans 1248*f0865ec9SKyle Evans /* Check if we support streaming */ 1249*f0865ec9SKyle Evans ret = is_verify_streaming_mode_supported(sig_type, &check); EG(ret, err); 1250*f0865ec9SKyle Evans if(check){ 1251*f0865ec9SKyle Evans /**** We support streaming mode ****/ 1252*f0865ec9SKyle Evans /* 1253*f0865ec9SKyle Evans * ... and read file content chunk by chunk to compute signature 1254*f0865ec9SKyle Evans */ 1255*f0865ec9SKyle Evans ret = ec_verify_init(&verif_ctx, &pub_key, sig, siglen, 1256*f0865ec9SKyle Evans sig_type, hash_type, (const u8*)adata, adata_len); 1257*f0865ec9SKyle Evans if (ret) { 1258*f0865ec9SKyle Evans ret = -1; 1259*f0865ec9SKyle Evans printf("Error: error when verifying ...\n"); 1260*f0865ec9SKyle Evans goto err; 1261*f0865ec9SKyle Evans } 1262*f0865ec9SKyle Evans 1263*f0865ec9SKyle Evans eof = 0; 1264*f0865ec9SKyle Evans clearerr(in_file); 1265*f0865ec9SKyle Evans while (exp_len && !eof) { 1266*f0865ec9SKyle Evans to_read = (exp_len < sizeof(buf)) ? exp_len : sizeof(buf); 1267*f0865ec9SKyle Evans read = fread(buf, 1, to_read, in_file); 1268*f0865ec9SKyle Evans if (read != to_read) { 1269*f0865ec9SKyle Evans /* Check if this was EOF */ 1270*f0865ec9SKyle Evans ret = feof(in_file); 1271*f0865ec9SKyle Evans clearerr(in_file); 1272*f0865ec9SKyle Evans if (ret) { 1273*f0865ec9SKyle Evans eof = 1; 1274*f0865ec9SKyle Evans } 1275*f0865ec9SKyle Evans } 1276*f0865ec9SKyle Evans 1277*f0865ec9SKyle Evans if (read > exp_len) { 1278*f0865ec9SKyle Evans /* we read more than expected: leave! */ 1279*f0865ec9SKyle Evans break; 1280*f0865ec9SKyle Evans } 1281*f0865ec9SKyle Evans 1282*f0865ec9SKyle Evans exp_len -= read; 1283*f0865ec9SKyle Evans 1284*f0865ec9SKyle Evans ret = ec_verify_update(&verif_ctx, buf, (u32)read); 1285*f0865ec9SKyle Evans if(ret){ 1286*f0865ec9SKyle Evans ret = -1; 1287*f0865ec9SKyle Evans printf("Error: error when verifying ...\n"); 1288*f0865ec9SKyle Evans goto err; 1289*f0865ec9SKyle Evans } 1290*f0865ec9SKyle Evans } 1291*f0865ec9SKyle Evans if (exp_len) { 1292*f0865ec9SKyle Evans ret = -1; 1293*f0865ec9SKyle Evans printf("Error: unable to read full file content\n"); 1294*f0865ec9SKyle Evans goto err; 1295*f0865ec9SKyle Evans } 1296*f0865ec9SKyle Evans ret = ec_verify_finalize(&verif_ctx); 1297*f0865ec9SKyle Evans if (ret) { 1298*f0865ec9SKyle Evans ret = -1; 1299*f0865ec9SKyle Evans goto err; 1300*f0865ec9SKyle Evans } 1301*f0865ec9SKyle Evans } 1302*f0865ec9SKyle Evans else{ 1303*f0865ec9SKyle Evans /**** We do not support streaming mode ****/ 1304*f0865ec9SKyle Evans /* Since we don't support streaming mode, we unfortunately have to 1305*f0865ec9SKyle Evans * use a dynamic allocation here. 1306*f0865ec9SKyle Evans */ 1307*f0865ec9SKyle Evans size_t offset = 0; 1308*f0865ec9SKyle Evans allocated_buff = (u8*)malloc(1); 1309*f0865ec9SKyle Evans 1310*f0865ec9SKyle Evans eof = 0; 1311*f0865ec9SKyle Evans clearerr(in_file); 1312*f0865ec9SKyle Evans while (exp_len && !eof) { 1313*f0865ec9SKyle Evans to_read = (exp_len < sizeof(buf)) ? exp_len : sizeof(buf); 1314*f0865ec9SKyle Evans read = fread(buf, 1, to_read, in_file); 1315*f0865ec9SKyle Evans if (read != to_read) { 1316*f0865ec9SKyle Evans /* Check if this was EOF */ 1317*f0865ec9SKyle Evans ret = feof(in_file); 1318*f0865ec9SKyle Evans clearerr(in_file); 1319*f0865ec9SKyle Evans if (ret) { 1320*f0865ec9SKyle Evans eof = 1; 1321*f0865ec9SKyle Evans } 1322*f0865ec9SKyle Evans } 1323*f0865ec9SKyle Evans 1324*f0865ec9SKyle Evans if (read > exp_len) { 1325*f0865ec9SKyle Evans /* we read more than expected: leave! */ 1326*f0865ec9SKyle Evans break; 1327*f0865ec9SKyle Evans } 1328*f0865ec9SKyle Evans 1329*f0865ec9SKyle Evans exp_len -= read; 1330*f0865ec9SKyle Evans 1331*f0865ec9SKyle Evans allocated_buff = (u8*)realloc(allocated_buff, offset + read); 1332*f0865ec9SKyle Evans if(allocated_buff == NULL){ 1333*f0865ec9SKyle Evans ret = -1; 1334*f0865ec9SKyle Evans printf("Error: allocation error\n"); 1335*f0865ec9SKyle Evans goto err; 1336*f0865ec9SKyle Evans } 1337*f0865ec9SKyle Evans memcpy(allocated_buff + offset, buf, read); 1338*f0865ec9SKyle Evans offset += read; 1339*f0865ec9SKyle Evans } 1340*f0865ec9SKyle Evans if (exp_len) { 1341*f0865ec9SKyle Evans ret = -1; 1342*f0865ec9SKyle Evans printf("Error: unable to read full file content\n"); 1343*f0865ec9SKyle Evans goto err; 1344*f0865ec9SKyle Evans } 1345*f0865ec9SKyle Evans 1346*f0865ec9SKyle Evans ret = ec_verify(sig, siglen, &pub_key, allocated_buff, (u32)offset, sig_type, hash_type, (const u8*)adata, adata_len); 1347*f0865ec9SKyle Evans if (ret) { 1348*f0865ec9SKyle Evans ret = -1; 1349*f0865ec9SKyle Evans goto err; 1350*f0865ec9SKyle Evans } 1351*f0865ec9SKyle Evans 1352*f0865ec9SKyle Evans } 1353*f0865ec9SKyle Evans 1354*f0865ec9SKyle Evans ret = 0; 1355*f0865ec9SKyle Evans 1356*f0865ec9SKyle Evans err: 1357*f0865ec9SKyle Evans if(in_file != NULL){ 1358*f0865ec9SKyle Evans if(fclose(in_file)){ 1359*f0865ec9SKyle Evans ret = -1; 1360*f0865ec9SKyle Evans } 1361*f0865ec9SKyle Evans } 1362*f0865ec9SKyle Evans if(in_key_file != NULL){ 1363*f0865ec9SKyle Evans if(fclose(in_key_file)){ 1364*f0865ec9SKyle Evans ret = -1; 1365*f0865ec9SKyle Evans } 1366*f0865ec9SKyle Evans } 1367*f0865ec9SKyle Evans if(in_sig_file != NULL){ 1368*f0865ec9SKyle Evans if(fclose(in_sig_file)){ 1369*f0865ec9SKyle Evans ret = -1; 1370*f0865ec9SKyle Evans } 1371*f0865ec9SKyle Evans } 1372*f0865ec9SKyle Evans if(allocated_buff != NULL){ 1373*f0865ec9SKyle Evans free(allocated_buff); 1374*f0865ec9SKyle Evans } 1375*f0865ec9SKyle Evans return ret; 1376*f0865ec9SKyle Evans } 1377*f0865ec9SKyle Evans 1378*f0865ec9SKyle Evans /* Compute 'scalar * Point' on the provided curve and prints 1379*f0865ec9SKyle Evans * the result. 1380*f0865ec9SKyle Evans */ 1381*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int ec_scalar_mult(const char *ec_name, 1382*f0865ec9SKyle Evans const char *scalar_file, 1383*f0865ec9SKyle Evans const char *point_file, 1384*f0865ec9SKyle Evans const char *outfile_name) 1385*f0865ec9SKyle Evans { 1386*f0865ec9SKyle Evans const ec_str_params *ec_str_p; 1387*f0865ec9SKyle Evans ec_params curve_params; 1388*f0865ec9SKyle Evans int ret; 1389*f0865ec9SKyle Evans u8 buf[MAX_BUF_LEN]; 1390*f0865ec9SKyle Evans size_t buf_len; 1391*f0865ec9SKyle Evans FILE *in_file = NULL; 1392*f0865ec9SKyle Evans FILE *out_file = NULL; 1393*f0865ec9SKyle Evans u16 coord_len; 1394*f0865ec9SKyle Evans 1395*f0865ec9SKyle Evans /* Scalar (natural number) to import */ 1396*f0865ec9SKyle Evans nn d; 1397*f0865ec9SKyle Evans /* Point to import */ 1398*f0865ec9SKyle Evans prj_pt Q; 1399*f0865ec9SKyle Evans d.magic = Q.magic = WORD(0); 1400*f0865ec9SKyle Evans 1401*f0865ec9SKyle Evans MUST_HAVE(ec_name != NULL, ret, err); 1402*f0865ec9SKyle Evans MUST_HAVE(scalar_file != NULL, ret, err); 1403*f0865ec9SKyle Evans MUST_HAVE(point_file != NULL, ret, err); 1404*f0865ec9SKyle Evans MUST_HAVE(outfile_name != NULL, ret, err); 1405*f0865ec9SKyle Evans 1406*f0865ec9SKyle Evans /* Get parameters from pretty names */ 1407*f0865ec9SKyle Evans ret = string_to_params(ec_name, NULL, NULL, &ec_str_p, 1408*f0865ec9SKyle Evans NULL, NULL); EG(ret, err); 1409*f0865ec9SKyle Evans 1410*f0865ec9SKyle Evans /* Import the parameters */ 1411*f0865ec9SKyle Evans ret = import_params(&curve_params, ec_str_p); EG(ret, err); 1412*f0865ec9SKyle Evans 1413*f0865ec9SKyle Evans /* Import the scalar in the local buffer from the file */ 1414*f0865ec9SKyle Evans /* Let's first get file size */ 1415*f0865ec9SKyle Evans ret = get_file_size(scalar_file, &buf_len); 1416*f0865ec9SKyle Evans if(buf_len == 0){ 1417*f0865ec9SKyle Evans ret = -1; 1418*f0865ec9SKyle Evans printf("Error: file %s seems to be empty!\n", scalar_file); 1419*f0865ec9SKyle Evans goto err; 1420*f0865ec9SKyle Evans } 1421*f0865ec9SKyle Evans if (ret) { 1422*f0865ec9SKyle Evans ret = -1; 1423*f0865ec9SKyle Evans printf("Error: cannot retrieve file %s size\n", scalar_file); 1424*f0865ec9SKyle Evans goto err; 1425*f0865ec9SKyle Evans } 1426*f0865ec9SKyle Evans if(buf_len > sizeof(buf)){ 1427*f0865ec9SKyle Evans ret = -1; 1428*f0865ec9SKyle Evans printf("Error: file %s content too large for our local buffers\n", scalar_file); 1429*f0865ec9SKyle Evans goto err; 1430*f0865ec9SKyle Evans } 1431*f0865ec9SKyle Evans /* Open main file to verify ... */ 1432*f0865ec9SKyle Evans in_file = fopen(scalar_file, "rb"); 1433*f0865ec9SKyle Evans if (in_file == NULL) { 1434*f0865ec9SKyle Evans ret = -1; 1435*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", scalar_file); 1436*f0865ec9SKyle Evans goto err; 1437*f0865ec9SKyle Evans } 1438*f0865ec9SKyle Evans /* Read the content of the file */ 1439*f0865ec9SKyle Evans if(fread(buf, 1, buf_len, in_file) != buf_len){ 1440*f0865ec9SKyle Evans ret = -1; 1441*f0865ec9SKyle Evans printf("Error: error when reading in %s\n", scalar_file); 1442*f0865ec9SKyle Evans goto err; 1443*f0865ec9SKyle Evans } 1444*f0865ec9SKyle Evans /* Import the scalar */ 1445*f0865ec9SKyle Evans ret = nn_init_from_buf(&d, buf, (u16)buf_len); EG(ret, err); 1446*f0865ec9SKyle Evans 1447*f0865ec9SKyle Evans /* Import the point in the local buffer from the file */ 1448*f0865ec9SKyle Evans /* Let's first get file size */ 1449*f0865ec9SKyle Evans ret = get_file_size(point_file, &buf_len); 1450*f0865ec9SKyle Evans if (ret) { 1451*f0865ec9SKyle Evans ret = -1; 1452*f0865ec9SKyle Evans printf("Error: cannot retrieve file %s size\n", point_file); 1453*f0865ec9SKyle Evans goto err; 1454*f0865ec9SKyle Evans } 1455*f0865ec9SKyle Evans if(buf_len > sizeof(buf)){ 1456*f0865ec9SKyle Evans ret = -1; 1457*f0865ec9SKyle Evans printf("Error: file %s content too large for our local buffers\n", point_file); 1458*f0865ec9SKyle Evans goto err; 1459*f0865ec9SKyle Evans } 1460*f0865ec9SKyle Evans ret = fclose(in_file); EG(ret, err); 1461*f0865ec9SKyle Evans in_file = NULL; 1462*f0865ec9SKyle Evans /* Open main file to verify ... */ 1463*f0865ec9SKyle Evans in_file = fopen(point_file, "rb"); 1464*f0865ec9SKyle Evans if (in_file == NULL) { 1465*f0865ec9SKyle Evans ret = -1; 1466*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", point_file); 1467*f0865ec9SKyle Evans goto err; 1468*f0865ec9SKyle Evans } 1469*f0865ec9SKyle Evans /* Read the content of the file */ 1470*f0865ec9SKyle Evans if(fread(buf, 1, buf_len, in_file) != buf_len){ 1471*f0865ec9SKyle Evans ret = -1; 1472*f0865ec9SKyle Evans printf("Error: error when reading in %s\n", point_file); 1473*f0865ec9SKyle Evans goto err; 1474*f0865ec9SKyle Evans } 1475*f0865ec9SKyle Evans /* Import the point */ 1476*f0865ec9SKyle Evans if(prj_pt_import_from_buf(&Q, buf, (u16)buf_len, &(curve_params.ec_curve))){ 1477*f0865ec9SKyle Evans ret = -1; 1478*f0865ec9SKyle Evans printf("Error: error when importing the projective point from %s\n", point_file); 1479*f0865ec9SKyle Evans goto err; 1480*f0865ec9SKyle Evans } 1481*f0865ec9SKyle Evans 1482*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING 1483*f0865ec9SKyle Evans /* NB: we use a blind scalar multiplication here since we do not want our 1484*f0865ec9SKyle Evans * private d to leak ... 1485*f0865ec9SKyle Evans */ 1486*f0865ec9SKyle Evans ret = prj_pt_mul_blind(&Q, &d, &Q); EG(ret, err); 1487*f0865ec9SKyle Evans #else 1488*f0865ec9SKyle Evans ret = prj_pt_mul(&Q, &d, &Q); EG(ret, err); 1489*f0865ec9SKyle Evans #endif 1490*f0865ec9SKyle Evans /* Get the unique representation of the point */ 1491*f0865ec9SKyle Evans ret = prj_pt_unique(&Q, &Q); EG(ret, err); 1492*f0865ec9SKyle Evans 1493*f0865ec9SKyle Evans /* Export the projective point in the local buffer */ 1494*f0865ec9SKyle Evans coord_len = (u16)(3 * BYTECEIL((Q.crv)->a.ctx->p_bitlen)); 1495*f0865ec9SKyle Evans if(coord_len > sizeof(buf)){ 1496*f0865ec9SKyle Evans ret = -1; 1497*f0865ec9SKyle Evans printf("Error: error when exporting the point\n"); 1498*f0865ec9SKyle Evans goto err; 1499*f0865ec9SKyle Evans } 1500*f0865ec9SKyle Evans if(prj_pt_export_to_buf(&Q, buf, coord_len)){ 1501*f0865ec9SKyle Evans ret = -1; 1502*f0865ec9SKyle Evans printf("Error: error when exporting the point\n"); 1503*f0865ec9SKyle Evans goto err; 1504*f0865ec9SKyle Evans } 1505*f0865ec9SKyle Evans /* Now save the coordinates in the output file */ 1506*f0865ec9SKyle Evans out_file = fopen(outfile_name, "wb"); 1507*f0865ec9SKyle Evans if (out_file == NULL) { 1508*f0865ec9SKyle Evans ret = -1; 1509*f0865ec9SKyle Evans printf("Error: file %s cannot be opened\n", outfile_name); 1510*f0865ec9SKyle Evans goto err; 1511*f0865ec9SKyle Evans } 1512*f0865ec9SKyle Evans 1513*f0865ec9SKyle Evans /* Write in the file */ 1514*f0865ec9SKyle Evans if(fwrite(buf, 1, coord_len, out_file) != coord_len){ 1515*f0865ec9SKyle Evans ret = -1; 1516*f0865ec9SKyle Evans printf("Error: error when writing to %s\n", outfile_name); 1517*f0865ec9SKyle Evans goto err; 1518*f0865ec9SKyle Evans } 1519*f0865ec9SKyle Evans 1520*f0865ec9SKyle Evans ret = 0; 1521*f0865ec9SKyle Evans 1522*f0865ec9SKyle Evans err: 1523*f0865ec9SKyle Evans /* Uninit local variables */ 1524*f0865ec9SKyle Evans nn_uninit(&d); 1525*f0865ec9SKyle Evans prj_pt_uninit(&Q); 1526*f0865ec9SKyle Evans 1527*f0865ec9SKyle Evans if(in_file != NULL){ 1528*f0865ec9SKyle Evans if(fclose(in_file)){ 1529*f0865ec9SKyle Evans ret = -1; 1530*f0865ec9SKyle Evans } 1531*f0865ec9SKyle Evans } 1532*f0865ec9SKyle Evans if(out_file != NULL){ 1533*f0865ec9SKyle Evans if(fclose(out_file)){ 1534*f0865ec9SKyle Evans ret = -1; 1535*f0865ec9SKyle Evans } 1536*f0865ec9SKyle Evans } 1537*f0865ec9SKyle Evans return ret; 1538*f0865ec9SKyle Evans } 1539*f0865ec9SKyle Evans 1540*f0865ec9SKyle Evans 1541*f0865ec9SKyle Evans static void print_curves(void) 1542*f0865ec9SKyle Evans { 1543*f0865ec9SKyle Evans u8 i; 1544*f0865ec9SKyle Evans 1545*f0865ec9SKyle Evans /* Print all the available curves */ 1546*f0865ec9SKyle Evans for (i = 0; i < EC_CURVES_NUM; i++) { 1547*f0865ec9SKyle Evans printf("%s ", (const char *)(ec_maps[i].params->name->buf)); 1548*f0865ec9SKyle Evans } 1549*f0865ec9SKyle Evans 1550*f0865ec9SKyle Evans return; 1551*f0865ec9SKyle Evans } 1552*f0865ec9SKyle Evans 1553*f0865ec9SKyle Evans static void print_hash_algs(void) 1554*f0865ec9SKyle Evans { 1555*f0865ec9SKyle Evans int i; 1556*f0865ec9SKyle Evans 1557*f0865ec9SKyle Evans /* Print all the available hash functions */ 1558*f0865ec9SKyle Evans for (i = 0; hash_maps[i].type != UNKNOWN_HASH_ALG; i++) { 1559*f0865ec9SKyle Evans printf("%s ", hash_maps[i].name); 1560*f0865ec9SKyle Evans } 1561*f0865ec9SKyle Evans 1562*f0865ec9SKyle Evans return; 1563*f0865ec9SKyle Evans } 1564*f0865ec9SKyle Evans 1565*f0865ec9SKyle Evans static void print_sig_algs(void) 1566*f0865ec9SKyle Evans { 1567*f0865ec9SKyle Evans int i; 1568*f0865ec9SKyle Evans 1569*f0865ec9SKyle Evans /* Print all the available signature schemes */ 1570*f0865ec9SKyle Evans for (i = 0; ec_sig_maps[i].type != UNKNOWN_ALG; i++) { 1571*f0865ec9SKyle Evans printf("%s ", ec_sig_maps[i].name); 1572*f0865ec9SKyle Evans } 1573*f0865ec9SKyle Evans 1574*f0865ec9SKyle Evans return; 1575*f0865ec9SKyle Evans } 1576*f0865ec9SKyle Evans 1577*f0865ec9SKyle Evans static void print_help(const char *prog_name) 1578*f0865ec9SKyle Evans { 1579*f0865ec9SKyle Evans printf("%s expects at least one argument\n", prog_name ? prog_name : "NULL"); 1580*f0865ec9SKyle Evans printf("\targ1 = 'gen_keys', 'sign', 'verify', 'struct_sign', 'struct_verify' or 'scalar_mult'\n"); 1581*f0865ec9SKyle Evans } 1582*f0865ec9SKyle Evans 1583*f0865ec9SKyle Evans #ifdef __cplusplus 1584*f0865ec9SKyle Evans /* In case of a C++ compiler, preserve our "main" 1585*f0865ec9SKyle Evans * linkage. 1586*f0865ec9SKyle Evans */ 1587*f0865ec9SKyle Evans extern "C" { 1588*f0865ec9SKyle Evans int main(int argc, char *argv[]); 1589*f0865ec9SKyle Evans } 1590*f0865ec9SKyle Evans #endif 1591*f0865ec9SKyle Evans 1592*f0865ec9SKyle Evans int main(int argc, char *argv[]) 1593*f0865ec9SKyle Evans { 1594*f0865ec9SKyle Evans int ret, check, found; 1595*f0865ec9SKyle Evans u32 len; 1596*f0865ec9SKyle Evans const char *adata = NULL; 1597*f0865ec9SKyle Evans u16 adata_len = 0; 1598*f0865ec9SKyle Evans 1599*f0865ec9SKyle Evans if (argc < 2) { 1600*f0865ec9SKyle Evans ret = -1; 1601*f0865ec9SKyle Evans print_help(argv[0]); 1602*f0865ec9SKyle Evans goto err; 1603*f0865ec9SKyle Evans } 1604*f0865ec9SKyle Evans 1605*f0865ec9SKyle Evans found = 0; 1606*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "gen_keys", &check); EG(ret, err); 1607*f0865ec9SKyle Evans if (check) { 1608*f0865ec9SKyle Evans found = 1; 1609*f0865ec9SKyle Evans /* Generate keys --------------------------------- 1610*f0865ec9SKyle Evans * 1611*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1612*f0865ec9SKyle Evans * arg2 = algorithm type ("ECDSA", "ECKCDSA", ...) 1613*f0865ec9SKyle Evans * arg3 = file name prefix 1614*f0865ec9SKyle Evans */ 1615*f0865ec9SKyle Evans if (argc != 5){ 1616*f0865ec9SKyle Evans ret = -1; 1617*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1618*f0865ec9SKyle Evans argv[1]); 1619*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1620*f0865ec9SKyle Evans print_curves(); 1621*f0865ec9SKyle Evans printf("\n"); 1622*f0865ec9SKyle Evans 1623*f0865ec9SKyle Evans printf("\targ2 = signature algorithm type: "); 1624*f0865ec9SKyle Evans print_sig_algs(); 1625*f0865ec9SKyle Evans printf("\n"); 1626*f0865ec9SKyle Evans 1627*f0865ec9SKyle Evans printf("\targ3 = file name prefix\n"); 1628*f0865ec9SKyle Evans printf("\n"); 1629*f0865ec9SKyle Evans 1630*f0865ec9SKyle Evans goto err; 1631*f0865ec9SKyle Evans } 1632*f0865ec9SKyle Evans if(generate_and_export_key_pair(argv[2], argv[3], argv[4])){ 1633*f0865ec9SKyle Evans ret = -1; 1634*f0865ec9SKyle Evans printf("gen_key error ...\n"); 1635*f0865ec9SKyle Evans goto err; 1636*f0865ec9SKyle Evans } 1637*f0865ec9SKyle Evans } 1638*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "sign", &check); EG(ret, err); 1639*f0865ec9SKyle Evans if (check) { 1640*f0865ec9SKyle Evans found = 1; 1641*f0865ec9SKyle Evans /* Sign something -------------------------------- 1642*f0865ec9SKyle Evans * Signature is structured, i.e. the output is a self contained 1643*f0865ec9SKyle Evans * data image 1644*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1645*f0865ec9SKyle Evans * arg2 = signature algorithm type ("ECDSA", "ECKCDSA", ...) 1646*f0865ec9SKyle Evans * arg3 = hash algorithm type ("SHA256", "SHA512", ...) 1647*f0865ec9SKyle Evans * arg4 = input file to sign 1648*f0865ec9SKyle Evans * arg5 = input file containing the private key 1649*f0865ec9SKyle Evans * arg6 = output file containing the signature 1650*f0865ec9SKyle Evans * arg7 (optional) = ancillary data to be used 1651*f0865ec9SKyle Evans */ 1652*f0865ec9SKyle Evans if ((argc != 8) && (argc != 9)) { 1653*f0865ec9SKyle Evans ret = -1; 1654*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1655*f0865ec9SKyle Evans argv[1]); 1656*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1657*f0865ec9SKyle Evans print_curves(); 1658*f0865ec9SKyle Evans printf("\n"); 1659*f0865ec9SKyle Evans 1660*f0865ec9SKyle Evans printf("\targ2 = signature algorithm type: "); 1661*f0865ec9SKyle Evans print_sig_algs(); 1662*f0865ec9SKyle Evans printf("\n"); 1663*f0865ec9SKyle Evans 1664*f0865ec9SKyle Evans printf("\targ3 = hash algorithm type: "); 1665*f0865ec9SKyle Evans print_hash_algs(); 1666*f0865ec9SKyle Evans printf("\n"); 1667*f0865ec9SKyle Evans 1668*f0865ec9SKyle Evans printf("\targ4 = input file to sign\n"); 1669*f0865ec9SKyle Evans printf("\targ5 = input file containing the private key (in raw binary format)\n"); 1670*f0865ec9SKyle Evans printf("\targ6 = output file containing the signature\n"); 1671*f0865ec9SKyle Evans printf("\t<arg7 (optional) = ancillary data to be used>\n"); 1672*f0865ec9SKyle Evans goto err; 1673*f0865ec9SKyle Evans } 1674*f0865ec9SKyle Evans if(argc == 9){ 1675*f0865ec9SKyle Evans adata = argv[8]; 1676*f0865ec9SKyle Evans ret = local_strlen(adata, &len); EG(ret, err); 1677*f0865ec9SKyle Evans MUST_HAVE(len <= 0xffff, ret, err); 1678*f0865ec9SKyle Evans adata_len = (u16)len; 1679*f0865ec9SKyle Evans } 1680*f0865ec9SKyle Evans if(sign_bin_file(argv[2], argv[3], argv[4], argv[5], argv[6], 1681*f0865ec9SKyle Evans argv[7], NULL, NULL, adata, adata_len)){ 1682*f0865ec9SKyle Evans ret = -1; 1683*f0865ec9SKyle Evans printf("sign error ...\n"); 1684*f0865ec9SKyle Evans goto err; 1685*f0865ec9SKyle Evans } 1686*f0865ec9SKyle Evans } 1687*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "verify", &check); EG(ret, err); 1688*f0865ec9SKyle Evans if (check) { 1689*f0865ec9SKyle Evans found = 1; 1690*f0865ec9SKyle Evans /* Verify something ------------------------------ 1691*f0865ec9SKyle Evans * 1692*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1693*f0865ec9SKyle Evans * arg2 = signature algorithm type ("ECDSA", "ECKCDSA", ...) 1694*f0865ec9SKyle Evans * arg3 = hash algorithm type ("SHA256", "SHA512", ...) 1695*f0865ec9SKyle Evans * arg = input file to verify 1696*f0865ec9SKyle Evans * arg5 = input file with the public key 1697*f0865ec9SKyle Evans * arg6 = input file containing the signature 1698*f0865ec9SKyle Evans * arg7 (optional) = ancillary data to be used 1699*f0865ec9SKyle Evans */ 1700*f0865ec9SKyle Evans if ((argc != 8) && (argc != 9)) { 1701*f0865ec9SKyle Evans ret = -1; 1702*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1703*f0865ec9SKyle Evans argv[1]); 1704*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1705*f0865ec9SKyle Evans print_curves(); 1706*f0865ec9SKyle Evans printf("\n"); 1707*f0865ec9SKyle Evans 1708*f0865ec9SKyle Evans printf("\targ2 = signature algorithm type: "); 1709*f0865ec9SKyle Evans print_sig_algs(); 1710*f0865ec9SKyle Evans printf("\n"); 1711*f0865ec9SKyle Evans 1712*f0865ec9SKyle Evans printf("\targ3 = hash algorithm type: "); 1713*f0865ec9SKyle Evans print_hash_algs(); 1714*f0865ec9SKyle Evans printf("\n"); 1715*f0865ec9SKyle Evans 1716*f0865ec9SKyle Evans printf("\targ4 = input file to verify\n"); 1717*f0865ec9SKyle Evans printf("\targ5 = input file containing the public key (in raw binary format)\n"); 1718*f0865ec9SKyle Evans printf("\targ6 = input file containing the signature\n"); 1719*f0865ec9SKyle Evans printf("\t<arg7 (optional) = ancillary data to be used>\n"); 1720*f0865ec9SKyle Evans goto err; 1721*f0865ec9SKyle Evans } 1722*f0865ec9SKyle Evans if(argc == 9){ 1723*f0865ec9SKyle Evans adata = argv[8]; 1724*f0865ec9SKyle Evans ret = local_strlen(adata, &len); EG(ret, err); 1725*f0865ec9SKyle Evans MUST_HAVE(len <= 0xffff, ret, err); 1726*f0865ec9SKyle Evans adata_len = (u16)len; 1727*f0865ec9SKyle Evans } 1728*f0865ec9SKyle Evans if (verify_bin_file(argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], adata, adata_len)) { 1729*f0865ec9SKyle Evans ret = -1; 1730*f0865ec9SKyle Evans printf("Signature check of %s failed\n", argv[5]); 1731*f0865ec9SKyle Evans goto err; 1732*f0865ec9SKyle Evans } else { 1733*f0865ec9SKyle Evans printf("Signature check of %s OK\n", argv[5]); 1734*f0865ec9SKyle Evans } 1735*f0865ec9SKyle Evans } 1736*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "struct_sign", &check); EG(ret, err); 1737*f0865ec9SKyle Evans if (check) { 1738*f0865ec9SKyle Evans found = 1; 1739*f0865ec9SKyle Evans /* Sign something -------------------------------- 1740*f0865ec9SKyle Evans * Signature is structured, i.e. the output is a self contained 1741*f0865ec9SKyle Evans * data image 1742*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1743*f0865ec9SKyle Evans * arg2 = signature algorithm type ("ECDSA", "ECKCDSA", ...) 1744*f0865ec9SKyle Evans * arg3 = hash algorithm type ("SHA256", "SHA512", ...) 1745*f0865ec9SKyle Evans * arg4 = input file to sign 1746*f0865ec9SKyle Evans * arg5 = input file with the private key 1747*f0865ec9SKyle Evans * arg6 = output file containing the appended signature 1748*f0865ec9SKyle Evans * arg7 = metadata header type 1749*f0865ec9SKyle Evans * arg8 = version of the metadata header 1750*f0865ec9SKyle Evans * arg9 (optional) = ancillary data to be used 1751*f0865ec9SKyle Evans */ 1752*f0865ec9SKyle Evans if ((argc != 10) && (argc != 11)) { 1753*f0865ec9SKyle Evans ret = -1; 1754*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1755*f0865ec9SKyle Evans argv[1]); 1756*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1757*f0865ec9SKyle Evans print_curves(); 1758*f0865ec9SKyle Evans printf("\n"); 1759*f0865ec9SKyle Evans 1760*f0865ec9SKyle Evans printf("\targ2 = signature algorithm type: "); 1761*f0865ec9SKyle Evans print_sig_algs(); 1762*f0865ec9SKyle Evans printf("\n"); 1763*f0865ec9SKyle Evans 1764*f0865ec9SKyle Evans printf("\targ3 = hash algorithm type: "); 1765*f0865ec9SKyle Evans print_hash_algs(); 1766*f0865ec9SKyle Evans printf("\n"); 1767*f0865ec9SKyle Evans 1768*f0865ec9SKyle Evans printf("\targ4 = input file to sign\n"); 1769*f0865ec9SKyle Evans printf("\targ5 = input file containing the private key (in raw binary format)\n"); 1770*f0865ec9SKyle Evans printf("\targ6 = output file containing the appended signature\n"); 1771*f0865ec9SKyle Evans printf("\targ7 = metadata header type (IMAGE_TYPE0, IMAGE_TYPE1, ...)\n"); 1772*f0865ec9SKyle Evans printf("\targ8 = version of the metadata header\n"); 1773*f0865ec9SKyle Evans printf("\t<arg9 (optional) = ancillary data to be used>\n"); 1774*f0865ec9SKyle Evans goto err; 1775*f0865ec9SKyle Evans } 1776*f0865ec9SKyle Evans if(argc == 11){ 1777*f0865ec9SKyle Evans adata = argv[10]; 1778*f0865ec9SKyle Evans ret = local_strlen(adata, &len); EG(ret, err); 1779*f0865ec9SKyle Evans MUST_HAVE(len <= 0xffff, ret, err); 1780*f0865ec9SKyle Evans adata_len = (u16)len; 1781*f0865ec9SKyle Evans } 1782*f0865ec9SKyle Evans if(sign_bin_file(argv[2], argv[3], argv[4], argv[5], argv[6], 1783*f0865ec9SKyle Evans argv[7], argv[8], argv[9], adata, adata_len)){ 1784*f0865ec9SKyle Evans ret = -1; 1785*f0865ec9SKyle Evans printf("struct_sign error ...\n"); 1786*f0865ec9SKyle Evans goto err; 1787*f0865ec9SKyle Evans } 1788*f0865ec9SKyle Evans } 1789*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "struct_verify", &check); EG(ret, err); 1790*f0865ec9SKyle Evans if (check) { 1791*f0865ec9SKyle Evans found = 1; 1792*f0865ec9SKyle Evans /* Verify something ------------------------------ 1793*f0865ec9SKyle Evans * 1794*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1795*f0865ec9SKyle Evans * arg2 = signature algorithm type ("ECDSA", "ECKCDSA", ...) 1796*f0865ec9SKyle Evans * arg3 = hash algorithm type ("SHA256", "SHA512", ...) 1797*f0865ec9SKyle Evans * arg4 = input file to verify 1798*f0865ec9SKyle Evans * arg5 = input file containing the public key (in raw binary format) 1799*f0865ec9SKyle Evans * arg6 (optional) = ancillary data to be used 1800*f0865ec9SKyle Evans */ 1801*f0865ec9SKyle Evans if ((argc != 7) && (argc != 8)) { 1802*f0865ec9SKyle Evans ret = -1; 1803*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1804*f0865ec9SKyle Evans argv[1]); 1805*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1806*f0865ec9SKyle Evans print_curves(); 1807*f0865ec9SKyle Evans printf("\n"); 1808*f0865ec9SKyle Evans 1809*f0865ec9SKyle Evans printf("\targ2 = signature algorithm type: "); 1810*f0865ec9SKyle Evans print_sig_algs(); 1811*f0865ec9SKyle Evans printf("\n"); 1812*f0865ec9SKyle Evans 1813*f0865ec9SKyle Evans printf("\targ3 = hash algorithm type: "); 1814*f0865ec9SKyle Evans print_hash_algs(); 1815*f0865ec9SKyle Evans printf("\n"); 1816*f0865ec9SKyle Evans 1817*f0865ec9SKyle Evans printf("\targ4 = input file to verify\n"); 1818*f0865ec9SKyle Evans printf("\targ5 = input file containing the public key (in raw binary format)\n"); 1819*f0865ec9SKyle Evans printf("\t<arg6 (optional) = ancillary data to be used>\n"); 1820*f0865ec9SKyle Evans goto err; 1821*f0865ec9SKyle Evans } 1822*f0865ec9SKyle Evans if(argc == 8){ 1823*f0865ec9SKyle Evans adata = argv[7]; 1824*f0865ec9SKyle Evans ret = local_strlen(adata, &len); EG(ret, err); 1825*f0865ec9SKyle Evans MUST_HAVE(len <= 0xffff, ret, err); 1826*f0865ec9SKyle Evans adata_len = (u16)len; 1827*f0865ec9SKyle Evans } 1828*f0865ec9SKyle Evans if (verify_bin_file(argv[2], argv[3], argv[4], argv[5], argv[6], NULL, adata, adata_len)) { 1829*f0865ec9SKyle Evans ret = -1; 1830*f0865ec9SKyle Evans printf("Signature check of %s failed\n", argv[5]); 1831*f0865ec9SKyle Evans goto err; 1832*f0865ec9SKyle Evans } else { 1833*f0865ec9SKyle Evans printf("Signature check of %s OK\n", argv[5]); 1834*f0865ec9SKyle Evans } 1835*f0865ec9SKyle Evans } 1836*f0865ec9SKyle Evans ret = are_str_equal(argv[1], "scalar_mult", &check); EG(ret, err); 1837*f0865ec9SKyle Evans if (check) { 1838*f0865ec9SKyle Evans found = 1; 1839*f0865ec9SKyle Evans /* Point scalar multiplication -------------------- 1840*f0865ec9SKyle Evans * 1841*f0865ec9SKyle Evans * arg1 = curve name ("frp256v1", ...) 1842*f0865ec9SKyle Evans * arg2 = scalar 1843*f0865ec9SKyle Evans * arg3 = point to multiply 1844*f0865ec9SKyle Evans * arg4 = file name where to save the result 1845*f0865ec9SKyle Evans */ 1846*f0865ec9SKyle Evans if (argc != 6) { 1847*f0865ec9SKyle Evans ret = -1; 1848*f0865ec9SKyle Evans printf("Bad args number for %s %s:\n", argv[0], 1849*f0865ec9SKyle Evans argv[1]); 1850*f0865ec9SKyle Evans printf("\targ1 = curve name: "); 1851*f0865ec9SKyle Evans print_curves(); 1852*f0865ec9SKyle Evans printf("\n"); 1853*f0865ec9SKyle Evans 1854*f0865ec9SKyle Evans printf("\targ2 = scalar bin file\n"); 1855*f0865ec9SKyle Evans printf("\targ3 = point to multiply bin file (projective coordinates)\n"); 1856*f0865ec9SKyle Evans printf("\targ4 = file name where to save the result\n"); 1857*f0865ec9SKyle Evans goto err; 1858*f0865ec9SKyle Evans } 1859*f0865ec9SKyle Evans if(ec_scalar_mult(argv[2], argv[3], argv[4], argv[5])){ 1860*f0865ec9SKyle Evans ret = -1; 1861*f0865ec9SKyle Evans printf("Scalar multiplication failed\n"); 1862*f0865ec9SKyle Evans goto err; 1863*f0865ec9SKyle Evans } 1864*f0865ec9SKyle Evans } 1865*f0865ec9SKyle Evans 1866*f0865ec9SKyle Evans if (found == 0) { 1867*f0865ec9SKyle Evans /* Bad first argument, print help */ 1868*f0865ec9SKyle Evans ret = -1; 1869*f0865ec9SKyle Evans printf("Bad first argument '%s'\n", argv[1]); 1870*f0865ec9SKyle Evans print_help(argv[0]); 1871*f0865ec9SKyle Evans goto err; 1872*f0865ec9SKyle Evans } 1873*f0865ec9SKyle Evans 1874*f0865ec9SKyle Evans ret = 0; 1875*f0865ec9SKyle Evans 1876*f0865ec9SKyle Evans err: 1877*f0865ec9SKyle Evans return ret; 1878*f0865ec9SKyle Evans } 1879