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