1 /* 2 * Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * Copyright (c) 2004, EdelKey Project. All Rights Reserved. 4 * 5 * Licensed under the OpenSSL license (the "License"). You may not use 6 * this file except in compliance with the License. You can obtain a copy 7 * in the file LICENSE in the source distribution or at 8 * https://www.openssl.org/source/license.html 9 * 10 * Originally written by Christophe Renou and Peter Sylvester, 11 * for the EdelKey project. 12 */ 13 14 #include <openssl/opensslconf.h> 15 #ifdef OPENSSL_NO_SRP 16 NON_EMPTY_TRANSLATION_UNIT 17 #else 18 19 # include <stdio.h> 20 # include <stdlib.h> 21 # include <string.h> 22 # include <openssl/conf.h> 23 # include <openssl/bio.h> 24 # include <openssl/err.h> 25 # include <openssl/txt_db.h> 26 # include <openssl/buffer.h> 27 # include <openssl/srp.h> 28 # include "apps.h" 29 # include "progs.h" 30 31 # define BASE_SECTION "srp" 32 # define CONFIG_FILE "openssl.cnf" 33 34 35 # define ENV_DATABASE "srpvfile" 36 # define ENV_DEFAULT_SRP "default_srp" 37 38 static int get_index(CA_DB *db, char *id, char type) 39 { 40 char **pp; 41 int i; 42 if (id == NULL) 43 return -1; 44 if (type == DB_SRP_INDEX) { 45 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { 46 pp = sk_OPENSSL_PSTRING_value(db->db->data, i); 47 if (pp[DB_srptype][0] == DB_SRP_INDEX 48 && strcmp(id, pp[DB_srpid]) == 0) 49 return i; 50 } 51 } else { 52 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { 53 pp = sk_OPENSSL_PSTRING_value(db->db->data, i); 54 55 if (pp[DB_srptype][0] != DB_SRP_INDEX 56 && strcmp(id, pp[DB_srpid]) == 0) 57 return i; 58 } 59 } 60 61 return -1; 62 } 63 64 static void print_entry(CA_DB *db, int indx, int verbose, char *s) 65 { 66 if (indx >= 0 && verbose) { 67 int j; 68 char **pp = sk_OPENSSL_PSTRING_value(db->db->data, indx); 69 BIO_printf(bio_err, "%s \"%s\"\n", s, pp[DB_srpid]); 70 for (j = 0; j < DB_NUMBER; j++) { 71 BIO_printf(bio_err, " %d = \"%s\"\n", j, pp[j]); 72 } 73 } 74 } 75 76 static void print_index(CA_DB *db, int indexindex, int verbose) 77 { 78 print_entry(db, indexindex, verbose, "g N entry"); 79 } 80 81 static void print_user(CA_DB *db, int userindex, int verbose) 82 { 83 if (verbose > 0) { 84 char **pp = sk_OPENSSL_PSTRING_value(db->db->data, userindex); 85 86 if (pp[DB_srptype][0] != 'I') { 87 print_entry(db, userindex, verbose, "User entry"); 88 print_entry(db, get_index(db, pp[DB_srpgN], 'I'), verbose, 89 "g N entry"); 90 } 91 92 } 93 } 94 95 static int update_index(CA_DB *db, char **row) 96 { 97 char **irow; 98 int i; 99 100 irow = app_malloc(sizeof(*irow) * (DB_NUMBER + 1), "row pointers"); 101 for (i = 0; i < DB_NUMBER; i++) 102 irow[i] = row[i]; 103 irow[DB_NUMBER] = NULL; 104 105 if (!TXT_DB_insert(db->db, irow)) { 106 BIO_printf(bio_err, "failed to update srpvfile\n"); 107 BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error); 108 OPENSSL_free(irow); 109 return 0; 110 } 111 return 1; 112 } 113 114 static char *lookup_conf(const CONF *conf, const char *section, const char *tag) 115 { 116 char *entry = NCONF_get_string(conf, section, tag); 117 if (entry == NULL) 118 BIO_printf(bio_err, "variable lookup failed for %s::%s\n", section, tag); 119 return entry; 120 } 121 122 static char *srp_verify_user(const char *user, const char *srp_verifier, 123 char *srp_usersalt, const char *g, const char *N, 124 const char *passin, int verbose) 125 { 126 char password[1025]; 127 PW_CB_DATA cb_tmp; 128 char *verifier = NULL; 129 char *gNid = NULL; 130 int len; 131 132 cb_tmp.prompt_info = user; 133 cb_tmp.password = passin; 134 135 len = password_callback(password, sizeof(password)-1, 0, &cb_tmp); 136 if (len > 0) { 137 password[len] = 0; 138 if (verbose) 139 BIO_printf(bio_err, 140 "Validating\n user=\"%s\"\n srp_verifier=\"%s\"\n srp_usersalt=\"%s\"\n g=\"%s\"\n N=\"%s\"\n", 141 user, srp_verifier, srp_usersalt, g, N); 142 if (verbose > 1) 143 BIO_printf(bio_err, "Pass %s\n", password); 144 145 OPENSSL_assert(srp_usersalt != NULL); 146 if ((gNid = SRP_create_verifier(user, password, &srp_usersalt, 147 &verifier, N, g)) == NULL) { 148 BIO_printf(bio_err, "Internal error validating SRP verifier\n"); 149 } else { 150 if (strcmp(verifier, srp_verifier)) 151 gNid = NULL; 152 OPENSSL_free(verifier); 153 } 154 OPENSSL_cleanse(password, len); 155 } 156 return gNid; 157 } 158 159 static char *srp_create_user(char *user, char **srp_verifier, 160 char **srp_usersalt, char *g, char *N, 161 char *passout, int verbose) 162 { 163 char password[1025]; 164 PW_CB_DATA cb_tmp; 165 char *gNid = NULL; 166 char *salt = NULL; 167 int len; 168 cb_tmp.prompt_info = user; 169 cb_tmp.password = passout; 170 171 len = password_callback(password, sizeof(password)-1, 1, &cb_tmp); 172 if (len > 0) { 173 password[len] = 0; 174 if (verbose) 175 BIO_printf(bio_err, "Creating\n user=\"%s\"\n g=\"%s\"\n N=\"%s\"\n", 176 user, g, N); 177 if ((gNid = SRP_create_verifier(user, password, &salt, 178 srp_verifier, N, g)) == NULL) { 179 BIO_printf(bio_err, "Internal error creating SRP verifier\n"); 180 } else { 181 *srp_usersalt = salt; 182 } 183 OPENSSL_cleanse(password, len); 184 if (verbose > 1) 185 BIO_printf(bio_err, "gNid=%s salt =\"%s\"\n verifier =\"%s\"\n", 186 gNid, salt, *srp_verifier); 187 188 } 189 return gNid; 190 } 191 192 typedef enum OPTION_choice { 193 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, 194 OPT_VERBOSE, OPT_CONFIG, OPT_NAME, OPT_SRPVFILE, OPT_ADD, 195 OPT_DELETE, OPT_MODIFY, OPT_LIST, OPT_GN, OPT_USERINFO, 196 OPT_PASSIN, OPT_PASSOUT, OPT_ENGINE, OPT_R_ENUM 197 } OPTION_CHOICE; 198 199 const OPTIONS srp_options[] = { 200 {"help", OPT_HELP, '-', "Display this summary"}, 201 {"verbose", OPT_VERBOSE, '-', "Talk a lot while doing things"}, 202 {"config", OPT_CONFIG, '<', "A config file"}, 203 {"name", OPT_NAME, 's', "The particular srp definition to use"}, 204 {"srpvfile", OPT_SRPVFILE, '<', "The srp verifier file name"}, 205 {"add", OPT_ADD, '-', "Add a user and srp verifier"}, 206 {"modify", OPT_MODIFY, '-', 207 "Modify the srp verifier of an existing user"}, 208 {"delete", OPT_DELETE, '-', "Delete user from verifier file"}, 209 {"list", OPT_LIST, '-', "List users"}, 210 {"gn", OPT_GN, 's', "Set g and N values to be used for new verifier"}, 211 {"userinfo", OPT_USERINFO, 's', "Additional info to be set for user"}, 212 {"passin", OPT_PASSIN, 's', "Input file pass phrase source"}, 213 {"passout", OPT_PASSOUT, 's', "Output file pass phrase source"}, 214 OPT_R_OPTIONS, 215 # ifndef OPENSSL_NO_ENGINE 216 {"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"}, 217 # endif 218 {NULL} 219 }; 220 221 int srp_main(int argc, char **argv) 222 { 223 ENGINE *e = NULL; 224 CA_DB *db = NULL; 225 CONF *conf = NULL; 226 int gNindex = -1, maxgN = -1, ret = 1, errors = 0, verbose = 0, i; 227 int doupdatedb = 0, mode = OPT_ERR; 228 char *user = NULL, *passinarg = NULL, *passoutarg = NULL; 229 char *passin = NULL, *passout = NULL, *gN = NULL, *userinfo = NULL; 230 char *section = NULL; 231 char **gNrow = NULL, *configfile = NULL; 232 char *srpvfile = NULL, **pp, *prog; 233 OPTION_CHOICE o; 234 235 prog = opt_init(argc, argv, srp_options); 236 while ((o = opt_next()) != OPT_EOF) { 237 switch (o) { 238 case OPT_EOF: 239 case OPT_ERR: 240 opthelp: 241 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); 242 goto end; 243 case OPT_HELP: 244 opt_help(srp_options); 245 ret = 0; 246 goto end; 247 case OPT_VERBOSE: 248 verbose++; 249 break; 250 case OPT_CONFIG: 251 configfile = opt_arg(); 252 break; 253 case OPT_NAME: 254 section = opt_arg(); 255 break; 256 case OPT_SRPVFILE: 257 srpvfile = opt_arg(); 258 break; 259 case OPT_ADD: 260 case OPT_DELETE: 261 case OPT_MODIFY: 262 case OPT_LIST: 263 if (mode != OPT_ERR) { 264 BIO_printf(bio_err, 265 "%s: Only one of -add/-delete/-modify/-list\n", 266 prog); 267 goto opthelp; 268 } 269 mode = o; 270 break; 271 case OPT_GN: 272 gN = opt_arg(); 273 break; 274 case OPT_USERINFO: 275 userinfo = opt_arg(); 276 break; 277 case OPT_PASSIN: 278 passinarg = opt_arg(); 279 break; 280 case OPT_PASSOUT: 281 passoutarg = opt_arg(); 282 break; 283 case OPT_ENGINE: 284 e = setup_engine(opt_arg(), 0); 285 break; 286 case OPT_R_CASES: 287 if (!opt_rand(o)) 288 goto end; 289 break; 290 } 291 } 292 argc = opt_num_rest(); 293 argv = opt_rest(); 294 295 if (srpvfile != NULL && configfile != NULL) { 296 BIO_printf(bio_err, 297 "-srpvfile and -configfile cannot be specified together.\n"); 298 goto end; 299 } 300 if (mode == OPT_ERR) { 301 BIO_printf(bio_err, 302 "Exactly one of the options -add, -delete, -modify -list must be specified.\n"); 303 goto opthelp; 304 } 305 if (mode == OPT_DELETE || mode == OPT_MODIFY || mode == OPT_ADD) { 306 if (argc == 0) { 307 BIO_printf(bio_err, "Need at least one user.\n"); 308 goto opthelp; 309 } 310 user = *argv++; 311 } 312 if ((passinarg != NULL || passoutarg != NULL) && argc != 1) { 313 BIO_printf(bio_err, 314 "-passin, -passout arguments only valid with one user.\n"); 315 goto opthelp; 316 } 317 318 if (!app_passwd(passinarg, passoutarg, &passin, &passout)) { 319 BIO_printf(bio_err, "Error getting passwords\n"); 320 goto end; 321 } 322 323 if (srpvfile == NULL) { 324 if (configfile == NULL) 325 configfile = default_config_file; 326 327 if (verbose) 328 BIO_printf(bio_err, "Using configuration from %s\n", 329 configfile); 330 conf = app_load_config(configfile); 331 if (conf == NULL) 332 goto end; 333 if (configfile != default_config_file && !app_load_modules(conf)) 334 goto end; 335 336 /* Lets get the config section we are using */ 337 if (section == NULL) { 338 if (verbose) 339 BIO_printf(bio_err, 340 "trying to read " ENV_DEFAULT_SRP 341 " in " BASE_SECTION "\n"); 342 343 section = lookup_conf(conf, BASE_SECTION, ENV_DEFAULT_SRP); 344 if (section == NULL) 345 goto end; 346 } 347 348 app_RAND_load_conf(conf, BASE_SECTION); 349 350 if (verbose) 351 BIO_printf(bio_err, 352 "trying to read " ENV_DATABASE " in section \"%s\"\n", 353 section); 354 355 srpvfile = lookup_conf(conf, section, ENV_DATABASE); 356 if (srpvfile == NULL) 357 goto end; 358 } 359 360 if (verbose) 361 BIO_printf(bio_err, "Trying to read SRP verifier file \"%s\"\n", 362 srpvfile); 363 364 db = load_index(srpvfile, NULL); 365 if (db == NULL) 366 goto end; 367 368 /* Lets check some fields */ 369 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { 370 pp = sk_OPENSSL_PSTRING_value(db->db->data, i); 371 372 if (pp[DB_srptype][0] == DB_SRP_INDEX) { 373 maxgN = i; 374 if ((gNindex < 0) && (gN != NULL) && strcmp(gN, pp[DB_srpid]) == 0) 375 gNindex = i; 376 377 print_index(db, i, verbose > 1); 378 } 379 } 380 381 if (verbose) 382 BIO_printf(bio_err, "Database initialised\n"); 383 384 if (gNindex >= 0) { 385 gNrow = sk_OPENSSL_PSTRING_value(db->db->data, gNindex); 386 print_entry(db, gNindex, verbose > 1, "Default g and N"); 387 } else if (maxgN > 0 && !SRP_get_default_gN(gN)) { 388 BIO_printf(bio_err, "No g and N value for index \"%s\"\n", gN); 389 goto end; 390 } else { 391 if (verbose) 392 BIO_printf(bio_err, "Database has no g N information.\n"); 393 gNrow = NULL; 394 } 395 396 if (verbose > 1) 397 BIO_printf(bio_err, "Starting user processing\n"); 398 399 while (mode == OPT_LIST || user != NULL) { 400 int userindex = -1; 401 402 if (user != NULL && verbose > 1) 403 BIO_printf(bio_err, "Processing user \"%s\"\n", user); 404 if ((userindex = get_index(db, user, 'U')) >= 0) 405 print_user(db, userindex, (verbose > 0) || mode == OPT_LIST); 406 407 if (mode == OPT_LIST) { 408 if (user == NULL) { 409 BIO_printf(bio_err, "List all users\n"); 410 411 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) 412 print_user(db, i, 1); 413 } else if (userindex < 0) { 414 BIO_printf(bio_err, 415 "user \"%s\" does not exist, ignored. t\n", user); 416 errors++; 417 } 418 } else if (mode == OPT_ADD) { 419 if (userindex >= 0) { 420 /* reactivation of a new user */ 421 char **row = 422 sk_OPENSSL_PSTRING_value(db->db->data, userindex); 423 BIO_printf(bio_err, "user \"%s\" reactivated.\n", user); 424 row[DB_srptype][0] = 'V'; 425 426 doupdatedb = 1; 427 } else { 428 char *row[DB_NUMBER]; 429 char *gNid; 430 row[DB_srpverifier] = NULL; 431 row[DB_srpsalt] = NULL; 432 row[DB_srpinfo] = NULL; 433 if (! 434 (gNid = 435 srp_create_user(user, &(row[DB_srpverifier]), 436 &(row[DB_srpsalt]), 437 gNrow ? gNrow[DB_srpsalt] : gN, 438 gNrow ? gNrow[DB_srpverifier] : NULL, 439 passout, verbose))) { 440 BIO_printf(bio_err, 441 "Cannot create srp verifier for user \"%s\", operation abandoned .\n", 442 user); 443 errors++; 444 goto end; 445 } 446 row[DB_srpid] = OPENSSL_strdup(user); 447 row[DB_srptype] = OPENSSL_strdup("v"); 448 row[DB_srpgN] = OPENSSL_strdup(gNid); 449 450 if ((row[DB_srpid] == NULL) 451 || (row[DB_srpgN] == NULL) 452 || (row[DB_srptype] == NULL) 453 || (row[DB_srpverifier] == NULL) 454 || (row[DB_srpsalt] == NULL) 455 || (userinfo 456 && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo)) == NULL)) 457 || !update_index(db, row)) { 458 OPENSSL_free(row[DB_srpid]); 459 OPENSSL_free(row[DB_srpgN]); 460 OPENSSL_free(row[DB_srpinfo]); 461 OPENSSL_free(row[DB_srptype]); 462 OPENSSL_free(row[DB_srpverifier]); 463 OPENSSL_free(row[DB_srpsalt]); 464 goto end; 465 } 466 doupdatedb = 1; 467 } 468 } else if (mode == OPT_MODIFY) { 469 if (userindex < 0) { 470 BIO_printf(bio_err, 471 "user \"%s\" does not exist, operation ignored.\n", 472 user); 473 errors++; 474 } else { 475 476 char **row = 477 sk_OPENSSL_PSTRING_value(db->db->data, userindex); 478 char type = row[DB_srptype][0]; 479 if (type == 'v') { 480 BIO_printf(bio_err, 481 "user \"%s\" already updated, operation ignored.\n", 482 user); 483 errors++; 484 } else { 485 char *gNid; 486 487 if (row[DB_srptype][0] == 'V') { 488 int user_gN; 489 char **irow = NULL; 490 if (verbose) 491 BIO_printf(bio_err, 492 "Verifying password for user \"%s\"\n", 493 user); 494 if ((user_gN = 495 get_index(db, row[DB_srpgN], DB_SRP_INDEX)) >= 0) 496 irow = 497 sk_OPENSSL_PSTRING_value(db->db->data, 498 userindex); 499 500 if (!srp_verify_user 501 (user, row[DB_srpverifier], row[DB_srpsalt], 502 irow ? irow[DB_srpsalt] : row[DB_srpgN], 503 irow ? irow[DB_srpverifier] : NULL, passin, 504 verbose)) { 505 BIO_printf(bio_err, 506 "Invalid password for user \"%s\", operation abandoned.\n", 507 user); 508 errors++; 509 goto end; 510 } 511 } 512 if (verbose) 513 BIO_printf(bio_err, "Password for user \"%s\" ok.\n", 514 user); 515 516 if (! 517 (gNid = 518 srp_create_user(user, &(row[DB_srpverifier]), 519 &(row[DB_srpsalt]), 520 gNrow ? gNrow[DB_srpsalt] : NULL, 521 gNrow ? gNrow[DB_srpverifier] : NULL, 522 passout, verbose))) { 523 BIO_printf(bio_err, 524 "Cannot create srp verifier for user \"%s\", operation abandoned.\n", 525 user); 526 errors++; 527 goto end; 528 } 529 530 row[DB_srptype][0] = 'v'; 531 row[DB_srpgN] = OPENSSL_strdup(gNid); 532 533 if (row[DB_srpid] == NULL 534 || row[DB_srpgN] == NULL 535 || row[DB_srptype] == NULL 536 || row[DB_srpverifier] == NULL 537 || row[DB_srpsalt] == NULL 538 || (userinfo 539 && ((row[DB_srpinfo] = OPENSSL_strdup(userinfo)) 540 == NULL))) 541 goto end; 542 543 doupdatedb = 1; 544 } 545 } 546 } else if (mode == OPT_DELETE) { 547 if (userindex < 0) { 548 BIO_printf(bio_err, 549 "user \"%s\" does not exist, operation ignored. t\n", 550 user); 551 errors++; 552 } else { 553 char **xpp = sk_OPENSSL_PSTRING_value(db->db->data, userindex); 554 555 BIO_printf(bio_err, "user \"%s\" revoked. t\n", user); 556 xpp[DB_srptype][0] = 'R'; 557 doupdatedb = 1; 558 } 559 } 560 user = *argv++; 561 if (user == NULL) { 562 /* no more processing in any mode if no users left */ 563 break; 564 } 565 } 566 567 if (verbose) 568 BIO_printf(bio_err, "User procession done.\n"); 569 570 if (doupdatedb) { 571 /* Lets check some fields */ 572 for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { 573 pp = sk_OPENSSL_PSTRING_value(db->db->data, i); 574 575 if (pp[DB_srptype][0] == 'v') { 576 pp[DB_srptype][0] = 'V'; 577 print_user(db, i, verbose); 578 } 579 } 580 581 if (verbose) 582 BIO_printf(bio_err, "Trying to update srpvfile.\n"); 583 if (!save_index(srpvfile, "new", db)) 584 goto end; 585 586 if (verbose) 587 BIO_printf(bio_err, "Temporary srpvfile created.\n"); 588 if (!rotate_index(srpvfile, "new", "old")) 589 goto end; 590 591 if (verbose) 592 BIO_printf(bio_err, "srpvfile updated.\n"); 593 } 594 595 ret = (errors != 0); 596 end: 597 if (errors != 0) 598 if (verbose) 599 BIO_printf(bio_err, "User errors %d.\n", errors); 600 601 if (verbose) 602 BIO_printf(bio_err, "SRP terminating with code %d.\n", ret); 603 604 OPENSSL_free(passin); 605 OPENSSL_free(passout); 606 if (ret) 607 ERR_print_errors(bio_err); 608 NCONF_free(conf); 609 free_index(db); 610 release_engine(e); 611 return ret; 612 } 613 #endif 614