1 /*
2    Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 /* C Headers */
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <stdint.h>
29 
30 /* C++ Headers */
31 #include <iostream>
32 #include <cstdlib>
33 #include <cstdio>
34 #include <string>
35 #include <sstream>
36 #include <fstream>
37 #include <algorithm>
38 
39 /* MySQL Headers */
40 #include <my_sys.h>
41 #include <my_dir.h>
42 #include <my_default.h>
43 #include <my_global.h>
44 #include <my_config.h>
45 #include <my_getopt.h>
46 #include <welcome_copyright_notice.h>   /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
47 #include <mysql_version.h>
48 #include "path.h"
49 #include "logger.h"
50 
51 #if HAVE_CHOWN
52 #include <pwd.h>
53 #endif
54 /* Utility Version */
55 #define MY_VERSION      "1.0.0"
56 
57 /* Forward declarations */
58 
59 using namespace std;
60 typedef string Sql_string_t;
61 
62 static Sql_string_t create_string(const char *ptr);
63 
64 /* Global Variables */
65 enum certs
66 {
67   CA_CERT=0,
68   CA_KEY,
69   CA_REQ,
70   SERVER_CERT,
71   SERVER_KEY,
72   SERVER_REQ,
73   CLIENT_CERT,
74   CLIENT_KEY,
75   CLIENT_REQ,
76   PRIVATE_KEY,
77   PUBLIC_KEY,
78   OPENSSL_RND
79 };
80 
81 enum extfiles
82 {
83   CAV3_EXT=0,
84   CERTV3_EXT
85 };
86 
87 Sql_string_t cert_files[] =
88 {
89   create_string("ca.pem"),
90   create_string("ca-key.pem"),
91   create_string("ca-req.pem"),
92   create_string("server-cert.pem"),
93   create_string("server-key.pem"),
94   create_string("server-req.pem"),
95   create_string("client-cert.pem"),
96   create_string("client-key.pem"),
97   create_string("client-req.pem"),
98   create_string("private_key.pem"),
99   create_string("public_key.pem"),
100   create_string(".rnd")
101 };
102 
103 Sql_string_t ext_files[] =
104 {
105   create_string("cav3.ext"),
106   create_string("certv3.ext")
107 };
108 
109 #define MAX_PATH_LEN  (FN_REFLEN - strlen(FN_DIRSEP) \
110                        - cert_files[SERVER_CERT].length() - 1)
111 /*
112   Higest number of fixed characters in subject line is 47:
113   MySQL_SERVER_<suffix>_Auto_Generated_Server_Certificate
114   Maximum size of subject is 64. So suffix can't be longer
115   than 17 characters.
116 */
117 #define MAX_SUFFIX_LEN 17
118 
119 Log info(cout,"NOTE");
120 Log error(cerr,"ERROR");
121 
122 char **defaults_argv= 0;
123 static char *opt_datadir= 0;
124 static char default_data_dir[]= MYSQL_DATADIR;
125 static char *opt_suffix= 0;
126 static char default_suffix[]= MYSQL_SERVER_VERSION;
127 #if HAVE_CHOWN
128 static char *opt_userid= 0;
129 struct passwd *user_info= 0;
130 #endif /* HAVE_CHOWN */
131 Path dir_string;
132 Sql_string_t suffix_string;
133 my_bool opt_verbose;
134 
135 static const char *load_default_groups[]=
136 {
137   "mysql_ssl_rsa_setup",
138   "mysql_install_db",
139   "mysqld",
140   0
141 };
142 
143 static struct my_option my_options[]= {
144   {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG,
145    NO_ARG, 0, 0, 0, 0, 0, 0},
146   {"verbose", 'v', "Be more verbose when running program",
147    &opt_verbose, 0, 0, GET_BOOL, NO_ARG, FALSE, 0, 0, 0, 0, 0},
148   {"version", 'V', "Print program version and exit", 0, 0, 0, GET_NO_ARG,
149    NO_ARG, 0, 0, 0, 0, 0, 0},
150   {"datadir", 'd', "Directory to store generated files.", &opt_datadir, &opt_datadir, 0,
151    GET_STR_ALLOC, REQUIRED_ARG, (longlong)&default_data_dir, 0, 0, 0, 0, 0},
152   {"suffix", 's',
153    "Suffix to be added in certificate subject line", &opt_suffix,
154    &opt_suffix, 0, GET_STR_ALLOC, REQUIRED_ARG, (longlong) &default_suffix,
155    0, 0, 0, 0, 0},
156 #if HAVE_CHOWN
157    {"uid", 0, "The effective user id to be used for file permission",
158     &opt_userid, &opt_userid, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0,
159     0, 0, 0},
160 #endif /* HAVE_CHOWN */
161   /* END TOKEN */
162   {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
163 };
164 
165 /* Helper Functions */
166 
167 /**
168   The string class will break if constructed with a NULL pointer. This wrapper
169   provides a systematic protection when importing char pointers.
170  */
171 static
create_string(const char * ptr)172 Sql_string_t create_string(const char *ptr)
173 {
174   return (ptr ? Sql_string_t(ptr) : Sql_string_t(""));
175 }
176 
177 
178 static
execute_command(const Sql_string_t & command,const Sql_string_t & error_message)179 int execute_command(const Sql_string_t &command,
180                     const Sql_string_t &error_message)
181 {
182   stringstream cmd_string;
183 
184   cmd_string << command;
185   if (!opt_verbose)
186   {
187 #ifndef _WIN32
188     cmd_string << " > /dev/null 2>&1";
189 #else
190     cmd_string << " > NUL 2>&1";
191 #endif /* _WIN32 */
192   }
193 
194   info << "Executing : " << cmd_string.str() << endl;
195   if (system(cmd_string.str().c_str()))
196   {
197     error << error_message << endl;
198     return 1;
199   }
200 
201   return 0;
202 }
203 
204 
205 static
set_file_pair_permission(const Sql_string_t & priv,const Sql_string_t & pub)206 int set_file_pair_permission(const Sql_string_t &priv,
207                              const Sql_string_t &pub)
208 {
209   if (MY_TEST(my_chmod(priv.c_str(),
210               USER_READ| USER_WRITE, MYF(MY_FAE+MY_WME))) ||
211       MY_TEST(my_chmod(pub.c_str(),
212               USER_READ|USER_WRITE|GROUP_READ|OTHERS_READ,
213               MYF(MY_FAE+MY_WME))))
214   {
215     error << "Error setting file permissions for" << priv.c_str()
216           << " and " << pub.c_str() << endl;
217     return 1;
218   }
219 #if HAVE_CHOWN
220   if (user_info)
221   {
222     if(chown(priv.c_str(), user_info->pw_uid, user_info->pw_gid) ||
223        chown(pub.c_str(), user_info->pw_uid, user_info->pw_gid))
224     {
225       error << "Failed to change file permission" << endl;
226       return 1;
227     }
228   }
229 #endif /* HAVE_CHOWN */
230   return 0;
231 }
232 
233 
234 static
file_exists(const Sql_string_t & filename)235 bool file_exists(const Sql_string_t &filename)
236 {
237   MY_STAT file_stat;
238   if (my_stat(filename.c_str(), &file_stat, MYF(0)) == NULL)
239     return false;
240 
241   return true;
242 }
243 
244 
245 static
remove_file(const Sql_string_t & filename,bool report_error=true)246 int remove_file(const Sql_string_t &filename, bool report_error=true)
247 {
248   if (my_delete(filename.c_str(), MYF(0)))
249   {
250     if (report_error)
251       error << "Error deleting : " << filename << endl;
252     return 1;
253   }
254   return 0;
255 }
256 
257 
258 static
free_resources()259 void free_resources()
260 {
261   if (opt_datadir)
262     my_free(opt_datadir);
263   if (opt_suffix)
264     my_free(opt_suffix);
265 #if HAVE_CHOWN
266   if (opt_userid)
267     my_free(opt_userid);
268 #endif
269   if (defaults_argv && *defaults_argv)
270     free_defaults(defaults_argv);
271 }
272 
273 
274 class RSA_priv
275 {
276 public:
RSA_priv(uint32_t key_size=2048)277   RSA_priv(uint32_t key_size= 2048)
278     : m_key_size(key_size) {};
279 
~RSA_priv()280   ~RSA_priv() {};
281 
operator ()(const Sql_string_t & key_file)282   Sql_string_t operator()(const Sql_string_t &key_file)
283   {
284     stringstream command;
285     command << "openssl genrsa " << " -out " << key_file << " " << m_key_size;
286 
287     return command.str();
288   }
289 private:
290   uint32_t m_key_size;
291 };
292 
293 
294 class RSA_pub
295 {
296 public:
operator ()(const Sql_string_t & priv_key_file,const Sql_string_t & pub_key_file)297   Sql_string_t operator()(const Sql_string_t &priv_key_file,
298                           const Sql_string_t &pub_key_file)
299   {
300     stringstream command;
301     command << "openssl rsa -in " << priv_key_file << " -pubout -out "
302             << pub_key_file;
303     return command.str();
304   }
305 };
306 
307 
308 class X509_key
309 {
310 public:
X509_key(const Sql_string_t & version,uint32_t validity=10* 365L)311   X509_key(const Sql_string_t &version,
312            uint32_t validity= 10*365L)
313     : m_validity(validity)
314   {
315     m_subj_prefix << "-subj /CN=MySQL_Server_" << version;
316   }
317 
operator ()(Sql_string_t suffix,const Sql_string_t & key_file,const Sql_string_t & req_file)318   Sql_string_t operator()(Sql_string_t suffix,
319                           const Sql_string_t &key_file,
320                           const Sql_string_t &req_file)
321   {
322     stringstream command;
323     command << "openssl req -newkey rsa:2048 -days " << m_validity
324             << " -nodes -keyout " << key_file << " "
325             << m_subj_prefix.str() << suffix << " -out " << req_file
326             << " && openssl rsa -in " << key_file << " -out " << key_file;
327 
328     return command.str();
329   }
330 
331 private:
332   uint32_t m_validity;
333   stringstream m_subj_prefix;
334 };
335 
336 class X509v3_ext_writer
337 {
338 public:
X509v3_ext_writer()339   X509v3_ext_writer()
340   {
341     m_cav3_ext_options << "basicConstraints=CA:TRUE" << std::endl;
342 
343     m_certv3_ext_options << "basicConstraints=CA:FALSE" << std::endl;
344   }
~X509v3_ext_writer()345   ~X509v3_ext_writer() {};
346 
operator ()(const Sql_string_t & cav3_ext_file,const Sql_string_t & certv3_ext_file)347   bool operator()(const Sql_string_t &cav3_ext_file,
348                   const Sql_string_t &certv3_ext_file)
349   {
350     if (!cav3_ext_file.length() ||
351         !certv3_ext_file.length())
352       return true;
353 
354     std::ofstream ext_file;
355 
356     ext_file.open(cav3_ext_file.c_str(),
357                   std::ios::out|std::ios::trunc);
358     if (!ext_file.is_open())
359       return true;
360     ext_file << m_cav3_ext_options.str();
361     ext_file.close();
362 
363     ext_file.open(certv3_ext_file.c_str(),
364                   std::ios::out|std::ios::trunc);
365     if (!ext_file.is_open())
366     {
367       remove_file(cav3_ext_file.c_str(), false);
368       return true;
369     }
370     ext_file << m_certv3_ext_options.str();
371     ext_file.close();
372 
373     return false;
374   }
375 private:
376   stringstream m_cav3_ext_options;
377   stringstream m_certv3_ext_options;
378 };
379 
380 class X509_cert
381 {
382 public:
X509_cert(uint32_t validity=10* 365L)383   X509_cert(uint32_t validity= 10*365L)
384     : m_validity(validity) {};
385 
~X509_cert()386   ~X509_cert() {};
387 
operator ()(const Sql_string_t & req_file,const Sql_string_t & cert_file,uint32_t serial,bool self_signed,const Sql_string_t & sign_key_file,const Sql_string_t & sign_cert_file,const Sql_string_t & ext_file)388   Sql_string_t operator()(const Sql_string_t &req_file,
389                           const Sql_string_t &cert_file,
390                           uint32_t serial,
391                           bool self_signed,
392                           const Sql_string_t &sign_key_file,
393                           const Sql_string_t &sign_cert_file,
394                           const Sql_string_t &ext_file)
395   {
396     stringstream command;
397     command << "openssl x509 -sha256 -days " << m_validity;
398     command << " -extfile " << ext_file;
399     command << " -set_serial " << serial << " -req -in " << req_file;
400     if (self_signed)
401       command << " -signkey " << sign_key_file;
402     else
403       command << " -CA " << sign_cert_file << " -CAkey " << sign_key_file;
404     command << " -out " << cert_file;
405 
406     return command.str();
407   }
408 
409 protected:
410   uint32_t m_validity;
411 };
412 
413 
414 static
print_version(void)415 void print_version(void)
416 {
417   cout << my_progname << " Version : " << MY_VERSION
418        << " Distribution : " << MYSQL_SERVER_VERSION
419        << " For : " << SYSTEM_TYPE << " On : " << MACHINE_TYPE << endl;
420 }
421 
422 
423 static
usage(void)424 void usage(void)
425 {
426   print_version();
427   cout << (ORACLE_WELCOME_COPYRIGHT_NOTICE("2015")) << endl
428        << "MySQL SSL Certificate and RSA Key Generation Utility" << endl
429        << "Usage : " << my_progname << " [OPTIONS]" << endl;
430 
431   my_print_help(my_options);
432   my_print_variables(my_options);
433 }
434 
435 
436 my_bool
my_arguments_get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)437 my_arguments_get_one_option(int optid,
438                             const struct my_option *opt MY_ATTRIBUTE((unused)),
439                             char *argument)
440 {
441   switch(optid){
442     case '?':
443       usage();
444       free_resources();
445       exit(0);
446     case 'V':
447       print_version();
448       free_resources();
449       exit(0);
450   }
451   return 0;
452 }
453 
454 
455 static inline
is_not_alnum_underscore(char c)456 bool is_not_alnum_underscore(char c)
457 {
458   return !(isalnum(c) || c == '_');
459 }
460 
461 static
check_suffix()462 bool check_suffix()
463 {
464   return (strcmp(opt_suffix, default_suffix) &&
465           (find_if(suffix_string.begin(), suffix_string.end(),
466                    is_not_alnum_underscore) != suffix_string.end()));
467 }
468 
469 
main(int argc,char * argv[])470 int main(int argc, char *argv[])
471 {
472   int ret_val= 0;
473   Sql_string_t openssl_check("openssl version");
474   my_bool save_skip_unknown= my_getopt_skip_unknown;
475 
476   MY_INIT(argv[0]);
477   DBUG_ENTER("main");
478   DBUG_PROCESS(argv[0]);
479 
480   /* Parse options : Command Line/Config file */
481 
482 #ifdef _WIN32
483   /* Convert command line parameters from UTF16LE to UTF8MB4. */
484   my_win_translate_command_line_args(&my_charset_utf8mb4_bin, &argc, &argv);
485 #endif
486   my_getopt_use_args_separator= TRUE;
487   if (load_defaults("my", load_default_groups, &argc, &argv))
488   {
489     my_end(0);
490     free_resources();
491     exit(1);
492   }
493 
494   MY_MODE file_creation_mode= get_file_perm(USER_READ | USER_WRITE);
495   MY_MODE saved_umask= umask(~(file_creation_mode));
496 
497   defaults_argv= argv;
498   my_getopt_use_args_separator= FALSE;
499   my_getopt_skip_unknown= TRUE;
500 
501   if (handle_options(&argc, &argv, my_options,
502                      my_arguments_get_one_option))
503   {
504     error << "Error parsing options" << endl;
505     ret_val= 1;
506     goto end;
507   }
508 
509   my_getopt_skip_unknown= save_skip_unknown;
510 
511   /* Process opt_verbose */
512   if (opt_verbose != TRUE)
513     info.enabled(false);
514 
515   /* Process opt_datadir */
516 
517   dir_string.path(create_string(opt_datadir));
518   if (dir_string.to_str().length() > MAX_PATH_LEN)
519   {
520     error << "Dir path is too long" << endl;
521     ret_val= 1;
522     goto end;
523   }
524 
525   if (!dir_string.normalize_path() || !dir_string.exists())
526   {
527     error << "Failed to access directory pointed by --datadir. "
528           << "Please make sure that directory exists and is "
529           << "accessible by mysql_ssl_rsa_setup. Supplied value : "
530           << dir_string.to_str() << endl;
531     ret_val= 1;
532     goto end;
533   }
534 
535   info << "Destination directory: " << dir_string.to_str() << endl;
536 
537   /* Process opt_suffix */
538 
539   suffix_string.append(opt_suffix);
540   if (suffix_string.length() > MAX_SUFFIX_LEN)
541   {
542     error << "Maximum number of characters allowed as the value for "
543           << "--suffix are " << MAX_SUFFIX_LEN << endl;
544     ret_val= 1;
545     goto end;
546   }
547 
548   if (check_suffix())
549   {
550     error << "Invalid string for --suffix option. Either use default value for "
551           << "the option or provide a string with alphanumeric characters "
552           << "and/or _ only." << endl;
553     ret_val= 1;
554     goto end;
555   }
556 
557   if ((ret_val= execute_command(openssl_check, "Could not find OpenSSL on the system")))
558   {
559     goto end;
560   }
561   else
562   {
563     char save_wd[FN_REFLEN];
564     bool files_exist= false;
565     Sql_string_t verify("openssl verify -CAfile ");
566 
567     if (my_getwd(save_wd, FN_REFLEN-1, MYF(MY_WME)))
568     {
569       error << "Error saving current working directory" << endl;
570       ret_val= 1;
571       goto end;
572     }
573 
574     if (my_setwd(dir_string.to_str().c_str(), MYF(MY_WME)))
575     {
576       error << "Error changing working directory" << endl;
577       ret_val= 1;
578       goto end;
579     }
580 #if HAVE_CHOWN
581     if (opt_userid && geteuid() == 0)
582     {
583       user_info= getpwnam(opt_userid);
584       if (!user_info)
585       {
586         error << "Error fetching user information" << endl;
587         ret_val= 1;
588         goto end;
589       }
590     }
591 #endif /* HAVE_CHOWN */
592 
593     /*
594       SSL Certificate Generation.
595       1. Check for ca.pem, server_cert.pem and server_key.pem at
596          the directory location provided by --dir.
597       2. If none of these files are present, generate following
598          files:
599          ca.pem, ca_key.pem
600          server_cert.pem, server_key.pem
601          client_cert.pem, client_key.pem
602       3. If everything goes smoothly, set permission on files.
603     */
604 
605     files_exist= file_exists(cert_files[CA_CERT]) ||
606                  file_exists(cert_files[SERVER_CERT]) ||
607                  file_exists(cert_files[SERVER_KEY]);
608 
609     if (files_exist)
610     {
611       info << "Certificate files are present in given dir. Skipping generation." << endl;
612     }
613     else
614     {
615       Sql_string_t empty_string("");
616       X509_key x509_key(suffix_string);
617       X509_cert x509_cert;
618       X509v3_ext_writer x509v3_ext_writer;
619 
620       /* Delete existing files if any */
621       remove_file(cert_files[CA_REQ], false);
622       remove_file(cert_files[SERVER_REQ], false);
623       remove_file(cert_files[CLIENT_REQ], false);
624       remove_file(cert_files[CLIENT_CERT], false);
625       remove_file(cert_files[CLIENT_KEY], false);
626       remove_file(cert_files[OPENSSL_RND], false);
627 
628       /* Remove existing v3 extension files */
629       remove_file(ext_files[CAV3_EXT], false);
630       remove_file(ext_files[CERTV3_EXT], false);
631 
632       /* Create v3 extension files */
633       if (x509v3_ext_writer(ext_files[CAV3_EXT], ext_files[CERTV3_EXT]))
634         goto end;
635 
636       /* Generate CA Key and Certificate */
637       if ((ret_val= execute_command(x509_key("_Auto_Generated_CA_Certificate",
638                                              cert_files[CA_KEY], cert_files[CA_REQ]),
639                                     "Error generating ca_key.pem and ca_req.pem")))
640         goto end;
641 
642       if ((ret_val= execute_command(x509_cert(cert_files[CA_REQ], cert_files[CA_CERT], 1,
643                                               true, cert_files[CA_KEY], empty_string,
644                                               ext_files[CAV3_EXT]),
645                                     "Error generating ca_cert.pem")))
646         goto end;
647 
648       /* Generate Server Key and Certificate */
649       if ((ret_val= execute_command(x509_key("_Auto_Generated_Server_Certificate",
650                                              cert_files[SERVER_KEY], cert_files[SERVER_REQ]),
651                                     "Error generating server_key.pem and server_req.pem")))
652         goto end;
653 
654       if ((ret_val= execute_command(x509_cert(cert_files[SERVER_REQ], cert_files[SERVER_CERT], 2,
655                                               false, cert_files[CA_KEY], cert_files[CA_CERT],
656                                               ext_files[CERTV3_EXT]),
657                                     "Error generating server_cert.pem")))
658         goto end;
659 
660       /* Generate Client Key and Certificate */
661       if ((ret_val= execute_command(x509_key("_Auto_Generated_Client_Certificate",
662                                              cert_files[CLIENT_KEY], cert_files[CLIENT_REQ]),
663                                     "Error generating client_key.pem and client_req.pem")))
664         goto end;
665 
666       if ((ret_val= execute_command(x509_cert(cert_files[CLIENT_REQ], cert_files[CLIENT_CERT], 3,
667                                               false, cert_files[CA_KEY], cert_files[CA_CERT],
668                                               ext_files[CERTV3_EXT]),
669                                     "Error generating client_cert.pem")))
670         goto end;
671 
672       /* Verify generated certificates */
673       verify.append(cert_files[CA_CERT]);
674       verify.append(" ");
675       verify.append(cert_files[SERVER_CERT]);
676       verify.append(" ");
677       verify.append(cert_files[CLIENT_CERT]);
678       if ((ret_val= execute_command(verify, "Verification of X509 certificates failed.")))
679         goto end;
680 
681       /* Set permission */
682       if ((ret_val= (set_file_pair_permission(cert_files[CA_KEY],
683                                               cert_files[CA_CERT]) |
684                      set_file_pair_permission(cert_files[SERVER_KEY],
685                                               cert_files[SERVER_CERT]) |
686                      set_file_pair_permission(cert_files[CLIENT_KEY],
687                                               cert_files[CLIENT_CERT]))))
688         goto end;
689 
690       /* Remove request files : Flag an error if we can't delete them. */
691       if ((ret_val= remove_file(cert_files[CA_REQ])))
692         goto end;
693 
694       if ((ret_val= remove_file(cert_files[SERVER_REQ])))
695         goto end;
696 
697       if ((ret_val= remove_file(cert_files[CLIENT_REQ])))
698         goto end;
699 
700       remove_file(cert_files[OPENSSL_RND], false);
701 
702       /* Remove existing v3 extension files */
703       remove_file(ext_files[CAV3_EXT], false);
704       remove_file(ext_files[CERTV3_EXT], false);
705 
706     }
707 
708     /*
709       RSA Key pair generation.
710       1. Check if private_key.pem or public_key.pem are present at
711          the directory location provided by --dir.
712       2. If not, generate private_key.pem, public_key.pem and
713          set permission after successful generation.
714     */
715 
716     files_exist= file_exists(cert_files[PRIVATE_KEY]) ||
717                  file_exists(cert_files[PUBLIC_KEY]);
718 
719     if (files_exist)
720     {
721       info << "RSA key files are present in given dir. Skipping generation." << endl;
722     }
723     else
724     {
725       RSA_priv rsa_priv;
726       RSA_pub rsa_pub;
727 
728       /* Remove existing file if any */
729       remove_file(cert_files[OPENSSL_RND], false);
730 
731       if ((ret_val= execute_command(rsa_priv(cert_files[PRIVATE_KEY]),
732               "Error generating private_key.pem")))
733         goto end;
734 
735       if ((ret_val= execute_command(rsa_pub(cert_files[PRIVATE_KEY],
736                                             cert_files[PUBLIC_KEY]),
737               "Error generating public_key.pem")))
738         goto end;
739       /* Set Permission */
740       if ((ret_val= set_file_pair_permission(cert_files[PRIVATE_KEY],
741                                              cert_files[PUBLIC_KEY])))
742         goto end;
743 
744       remove_file(cert_files[OPENSSL_RND], false);
745     }
746 
747     if (my_setwd(save_wd, MYF(MY_WME)))
748     {
749       error << "Error changing working directory" << endl;
750       ret_val= 1;
751       goto end;
752     }
753   }
754 
755   info << "Success!" << endl;
756 
757 end:
758 
759   umask(saved_umask);
760   free_resources();
761 
762   DBUG_RETURN(ret_val);
763 }
764