23 #ifdef PRC_PUBLIC_KEYS_INCLUDE 24 #include PRC_PUBLIC_KEYS_INCLUDE 27 #include <openssl/rsa.h> 28 #include <openssl/err.h> 29 #include <openssl/pem.h> 30 #include <openssl/rand.h> 31 #include <openssl/bio.h> 39 bool _got_pass_phrase;
51 cerr <<
"Error occurred in SSL routines.\n";
53 static bool strings_loaded =
false;
54 if (!strings_loaded) {
55 ERR_load_crypto_strings();
56 strings_loaded =
true;
59 unsigned long e = ERR_get_error();
61 static const size_t buffer_len = 256;
62 char buffer[buffer_len];
63 ERR_error_string_n(e, buffer, buffer_len);
64 cerr << buffer <<
"\n";
76 size_t index, BIO *mbio) {
78 size_t data_size = BIO_get_mem_data(mbio, &data_ptr);
80 out <<
"static const char * const " << string_name
81 << index <<
"_data =\n" 85 for (
size_t i = 0; i < data_size; i++) {
86 if (data_ptr[i] ==
'\n') {
96 if (isprint(data_ptr[i])) {
100 out <<
"\\x" << std::hex << std::setw(2) << std::setfill(
'0')
101 << (
unsigned int)(
unsigned char)data_ptr[i] << std::dec;
105 out <<
"\";\nstatic const unsigned int " << string_name << index
106 <<
"_length = " << data_size <<
";\n";
114 RSA *rsa = RSA_new();
115 BIGNUM *e = BN_new();
116 if (rsa ==
nullptr || e ==
nullptr) {
123 if (!RSA_generate_key_ex(rsa, 1024, e,
nullptr)) {
131 EVP_PKEY *pkey = EVP_PKEY_new();
132 EVP_PKEY_assign_RSA(pkey, rsa);
144 cerr <<
"Rewriting " << outfile <<
"\n";
147 if (!outfile.open_write(out)) {
148 cerr <<
"Unable to open " << outfile <<
" for writing.\n";
154 "// This file was generated by make-prc-key. It defines the public keys\n" 155 "// that will be used to validate signed prc files.\n" 157 "#include \"prcKeyRegistry.h\"\n" 160 PrcKeyRegistry *pkr = PrcKeyRegistry::get_global_ptr();
162 BIO *mbio = BIO_new(BIO_s_mem());
164 size_t num_keys = pkr->get_num_keys();
166 for (i = 0; i < num_keys; i++) {
167 EVP_PKEY *pkey = pkr->get_key(i);
169 if (pkey !=
nullptr) {
170 if (!PEM_write_bio_PUBKEY(mbio, pkey)) {
176 (void)BIO_reset(mbio);
184 out <<
"static PrcKeyRegistry::KeyDef const prc_pubkeys[" << num_keys <<
"] = {\n";
186 for (i = 0; i < num_keys; i++) {
187 EVP_PKEY *pkey = pkr->get_key(i);
188 time_t generated_time = pkr->get_generated_time(i);
190 if (pkey !=
nullptr) {
191 out <<
" { prc_pubkey" << i <<
"_data, prc_pubkey" << i
192 <<
"_length, " << generated_time <<
" },\n";
194 out <<
" { nullptr, 0, 0 },\n";
199 <<
"static const int num_prc_pubkeys = " << num_keys <<
";\n\n";
210 cerr <<
"Rewriting " << outfile <<
"\n";
213 if (!outfile.open_write(out)) {
214 cerr <<
"Unable to open " << outfile <<
" for writing.\n";
220 "// This file was generated by make-prc-key. It can be compiled against\n" 221 "// dtool to produce a program that will sign a prc file using key number " << n <<
".\n\n";
223 BIO *mbio = BIO_new(BIO_s_mem());
226 if (pp !=
nullptr && *pp ==
'\0') {
230 PEM_write_bio_PKCS8PrivateKey(mbio, pkey,
nullptr,
nullptr, 0,
nullptr,
nullptr);
235 PEM_write_bio_PKCS8PrivateKey(mbio, pkey, EVP_des_ede3_cbc(),
236 nullptr, 0,
nullptr, (
void *)pp);
250 "#define KEY_NUMBER " << n <<
"\n" 251 "#define KEY_DATA prc_privkey" << n <<
"_data\n" 252 "#define KEY_LENGTH prc_privkey" << n <<
"_length\n" 253 "#define PROGNAME \"" << outfile.get_basename_wo_extension() <<
"\"\n" 254 "#define GENERATED_TIME " << now <<
"\n\n" 256 "#include \"signPrcFile_src.cxx\"\n\n";
265 "\nmake-prc-key [opts] 1[,\"pass_phrase\"] [2[,\"pass phrase\"] 3 ...]\n\n" 267 "This program generates one or more new keys to be used for signing\n" 268 "a prc file. The key itself is a completely arbitrary random bit\n" 269 "sequence. It is divided into a public and a private key; the public\n" 270 "key is not secret and will be compiled into libdtool, while the private\n" 271 "key should be safeguarded and will be written into a .cxx file that\n" 272 "can be compiled as a standalone application.\n\n" 274 "The output is a public and private key pair for each trust level. The\n" 275 "form of the output for both public and private keys will be compilable\n" 276 "C++ code; see -a and -b, below, for a complete description.\n\n" 278 "After the options, the remaining arguments list the individual trust\n" 279 "level keys to generate. For each integer specified, a different key\n" 280 "will be created. There should be one key for each trust level\n" 281 "required; a typical application will only need one or two keys.\n\n" 285 " -a pub_outfile.cxx\n" 286 " Specifies the name and location of the public key output file\n" 287 " to generate. This file must then be named by the Config.pp\n" 288 " variable PRC_PUBLIC_KEYS_FILENAME so that it will be compiled\n" 289 " in with libdtool and available to verify signatures. If this\n" 290 " option is omitted, the previously-compiled value is used.\n\n" 292 " -b priv_outfile#.cxx\n" 293 " Specifies the name and location of the private key output file(s)\n" 294 " to generate. A different output file will be generated for each\n" 295 " different trust level; the hash mark '#' appearing in the file\n" 296 " name will be filled in with the corresponding numeric trust level.\n" 297 " The hash mark may be omitted if you only require one trust level.\n" 298 " When compiled against dtool, each of these files will generate\n" 299 " a program that can be used to sign a prc file with the corresponding\n" 302 " -p \"[pass phrase]\"\n" 303 " Uses the indicated pass phrase to encrypt the private key.\n" 304 " This specifies an overall pass phrase; you may also specify\n" 305 " a different pass phrase for each key by using the key,\"pass phrase\"\n" 308 " If a pass phrase is not specified on the command line, you will be\n" 309 " prompted interactively. Every user of the signing programs\n" 310 " (outfile_sign1.cxx, etc.) will need to know the pass phrase\n" 311 " in order to sign prc files.\n\n" 313 " If this is specified as the empty string (\"\"), then the key\n" 314 " will not be encrypted, and anyone can run the signing\n" 315 " programs without having to supply a pass phrase.\n\n";
322 main(
int argc,
char **argv) {
325 const char *optstr =
"a:b:p:h";
328 bool got_pub_outfile =
false;
330 bool got_priv_outfile =
false;
332 bool got_pass_phrase =
false;
335 int flag = getopt(argc, argv, optstr);
337 while (flag != EOF) {
340 pub_outfile = optarg;
341 got_pub_outfile =
true;
345 priv_outfile = optarg;
346 got_priv_outfile =
true;
350 pass_phrase = optarg;
351 got_pass_phrase =
true;
361 flag = getopt(argc, argv, optstr);
372 if (got_pub_outfile) {
374 cerr <<
"Public key output file '" << pub_outfile
375 <<
"' should have a .cxx extension.\n";
379 #ifdef PRC_PUBLIC_KEYS_INCLUDE 380 PrcKeyRegistry::get_global_ptr()->record_keys(prc_pubkeys, num_prc_pubkeys);
381 pub_outfile = PRC_PUBLIC_KEYS_FILENAME;
384 if (pub_outfile.empty()) {
385 cerr <<
"No -a specified, and no PRC_PUBLIC_KEYS_FILENAME variable\n" 386 <<
"compiled in.\n\n";
391 if (got_priv_outfile) {
393 cerr <<
"Private key output file '" << priv_outfile
394 <<
"' should have a .cxx extension.\n";
399 cerr <<
"You must use the -b option to specify the private key output filenames.\n";
404 for (
int i = 1; i < argc; i++) {
407 key._number = (int)strtol(argv[i], &endptr, 0);
408 key._got_pass_phrase = got_pass_phrase;
409 key._pass_phrase = pass_phrase;
411 if (*endptr ==
',') {
413 key._got_pass_phrase =
true;
414 key._pass_phrase = endptr + 1;
415 }
else if (*endptr) {
416 cerr <<
"Parameter '" << argv[i] <<
"' should be an integer.\n";
419 if (key._number <= 0) {
420 cerr <<
"Key numbers must be greater than 0; you specified " 421 << key._number <<
".\n";
424 key_numbers.push_back(key);
431 OpenSSL_add_all_algorithms();
433 time_t now = time(
nullptr);
436 string prefix, suffix;
439 size_t hash = name.find(
'#');
440 if (hash == string::npos) {
446 prefix = name.substr(0, hash);
447 suffix = name.substr(hash + 1) +
".cxx";
451 KeyNumbers::iterator ki;
452 for (ki = key_numbers.begin(); ki != key_numbers.end(); ++ki) {
453 int n = (*ki)._number;
454 const char *pp =
nullptr;
455 if ((*ki)._got_pass_phrase) {
456 pp = (*ki)._pass_phrase.c_str();
460 PrcKeyRegistry::get_global_ptr()->set_key(n, pkey, now);
462 std::ostringstream strm;
463 if (got_hash || n != 1) {
467 strm << prefix << n << suffix;
473 strm << prefix << suffix;
void set_text()
Indicates that the filename represents a text file.
void write_public_keys(Filename outfile)
Writes the list of public keys stored in the PrcKeyRegistry to the indicated output filename as a com...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void output_ssl_errors()
A convenience function that is itself a wrapper around the OpenSSL convenience function to output the...
void write_private_key(EVP_PKEY *pkey, Filename outfile, int n, time_t now, const char *pp)
Generates a C++ program that can be used to sign a prc file with the indicated private key into the g...
This is our own Panda specialization on the default STL vector.
EVP_PKEY * generate_key()
Generates a new public and private key pair.
The name of a file, such as a texture file or an Egg file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::string get_extension() const
Returns the file extension.
void preprocess_argv(int &argc, char **&argv)
Processes the argc, argv pair as needed before passing it to getopt().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void output_c_string(std::ostream &out, const string &string_name, size_t index, BIO *mbio)
Extracts the data written to the indicated memory bio and writes it to the indicated stream,...
std::string get_fullpath_wo_extension() const
Returns the full filename–directory and basename parts–except for the extension.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.