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