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 (data_ptr[i] ==
'\t') {
99 else if (isprint(data_ptr[i])) {
103 out <<
"\\x" << std::hex << std::setw(2) << std::setfill(
'0')
104 << (
unsigned int)(
unsigned char)data_ptr[i] << std::dec;
108 out <<
"\";\nstatic const unsigned int " << string_name << index
109 <<
"_length = " << data_size <<
";\n";
117 RSA *rsa = RSA_new();
118 BIGNUM *e = BN_new();
119 if (rsa ==
nullptr || e ==
nullptr) {
126 if (!RSA_generate_key_ex(rsa, 1024, e,
nullptr)) {
134 EVP_PKEY *pkey = EVP_PKEY_new();
135 EVP_PKEY_assign_RSA(pkey, rsa);
147 cerr <<
"Rewriting " << outfile <<
"\n";
151 cerr <<
"Unable to open " << outfile <<
" for writing.\n";
157 "// This file was generated by make-prc-key. It defines the public keys\n"
158 "// that will be used to validate signed prc files.\n"
160 "#include \"prcKeyRegistry.h\"\n"
163 PrcKeyRegistry *pkr = PrcKeyRegistry::get_global_ptr();
165 BIO *mbio = BIO_new(BIO_s_mem());
167 size_t num_keys = pkr->get_num_keys();
169 for (i = 0; i < num_keys; i++) {
170 EVP_PKEY *pkey = pkr->get_key(i);
172 if (pkey !=
nullptr) {
173 if (!PEM_write_bio_PUBKEY(mbio, pkey)) {
179 (void)BIO_reset(mbio);
187 out <<
"static PrcKeyRegistry::KeyDef const prc_pubkeys[" << num_keys <<
"] = {\n";
189 for (i = 0; i < num_keys; i++) {
190 EVP_PKEY *pkey = pkr->get_key(i);
191 time_t generated_time = pkr->get_generated_time(i);
193 if (pkey !=
nullptr) {
194 out <<
" { prc_pubkey" << i <<
"_data, prc_pubkey" << i
195 <<
"_length, " << generated_time <<
" },\n";
197 out <<
" { nullptr, 0, 0 },\n";
202 <<
"static const int num_prc_pubkeys = " << num_keys <<
";\n\n";
213 cerr <<
"Rewriting " << outfile <<
"\n";
217 cerr <<
"Unable to open " << outfile <<
" for writing.\n";
223 "// This file was generated by make-prc-key. It can be compiled against\n"
224 "// dtool to produce a program that will sign a prc file using key number " << n <<
".\n\n";
226 BIO *mbio = BIO_new(BIO_s_mem());
229 if (pp !=
nullptr && *pp ==
'\0') {
233 PEM_write_bio_PKCS8PrivateKey(mbio, pkey,
nullptr,
nullptr, 0,
nullptr,
nullptr);
238 PEM_write_bio_PKCS8PrivateKey(mbio, pkey, EVP_des_ede3_cbc(),
239 nullptr, 0,
nullptr, (
void *)pp);
253 "#define KEY_NUMBER " << n <<
"\n"
254 "#define KEY_DATA prc_privkey" << n <<
"_data\n"
255 "#define KEY_LENGTH prc_privkey" << n <<
"_length\n"
257 "#define GENERATED_TIME " << now <<
"\n\n"
259 "#include \"signPrcFile_src.cxx\"\n\n";
268 "\nmake-prc-key [opts] 1[,\"pass_phrase\"] [2[,\"pass phrase\"] 3 ...]\n\n"
270 "This program generates one or more new keys to be used for signing\n"
271 "a prc file. The key itself is a completely arbitrary random bit\n"
272 "sequence. It is divided into a public and a private key; the public\n"
273 "key is not secret and will be compiled into libdtool, while the private\n"
274 "key should be safeguarded and will be written into a .cxx file that\n"
275 "can be compiled as a standalone application.\n\n"
277 "The output is a public and private key pair for each trust level. The\n"
278 "form of the output for both public and private keys will be compilable\n"
279 "C++ code; see -a and -b, below, for a complete description.\n\n"
281 "After the options, the remaining arguments list the individual trust\n"
282 "level keys to generate. For each integer specified, a different key\n"
283 "will be created. There should be one key for each trust level\n"
284 "required; a typical application will only need one or two keys.\n\n"
288 " -a pub_outfile.cxx\n"
289 " Specifies the name and location of the public key output file\n"
290 " to generate. This file must then be named by the Config.pp\n"
291 " variable PRC_PUBLIC_KEYS_FILENAME so that it will be compiled\n"
292 " in with libdtool and available to verify signatures. If this\n"
293 " option is omitted, the previously-compiled value is used.\n\n"
295 " -b priv_outfile#.cxx\n"
296 " Specifies the name and location of the private key output file(s)\n"
297 " to generate. A different output file will be generated for each\n"
298 " different trust level; the hash mark '#' appearing in the file\n"
299 " name will be filled in with the corresponding numeric trust level.\n"
300 " The hash mark may be omitted if you only require one trust level.\n"
301 " When compiled against dtool, each of these files will generate\n"
302 " a program that can be used to sign a prc file with the corresponding\n"
305 " -p \"[pass phrase]\"\n"
306 " Uses the indicated pass phrase to encrypt the private key.\n"
307 " This specifies an overall pass phrase; you may also specify\n"
308 " a different pass phrase for each key by using the key,\"pass phrase\"\n"
311 " If a pass phrase is not specified on the command line, you will be\n"
312 " prompted interactively. Every user of the signing programs\n"
313 " (outfile_sign1.cxx, etc.) will need to know the pass phrase\n"
314 " in order to sign prc files.\n\n"
316 " If this is specified as the empty string (\"\"), then the key\n"
317 " will not be encrypted, and anyone can run the signing\n"
318 " programs without having to supply a pass phrase.\n\n";
325main(
int argc,
char **argv) {
328 const char *optstr =
"a:b:p:h";
331 bool got_pub_outfile =
false;
333 bool got_priv_outfile =
false;
335 bool got_pass_phrase =
false;
338 int flag = getopt(argc, argv, optstr);
340 while (flag != EOF) {
343 pub_outfile = optarg;
344 got_pub_outfile =
true;
348 priv_outfile = optarg;
349 got_priv_outfile =
true;
353 pass_phrase = optarg;
354 got_pass_phrase =
true;
364 flag = getopt(argc, argv, optstr);
375 if (got_pub_outfile) {
377 cerr <<
"Public key output file '" << pub_outfile
378 <<
"' should have a .cxx extension.\n";
382#ifdef PRC_PUBLIC_KEYS_INCLUDE
383 PrcKeyRegistry::get_global_ptr()->record_keys(prc_pubkeys, num_prc_pubkeys);
384 pub_outfile = PRC_PUBLIC_KEYS_FILENAME;
387 if (pub_outfile.empty()) {
388 cerr <<
"No -a specified, and no PRC_PUBLIC_KEYS_FILENAME variable\n"
389 <<
"compiled in.\n\n";
394 if (got_priv_outfile) {
396 cerr <<
"Private key output file '" << priv_outfile
397 <<
"' should have a .cxx extension.\n";
402 cerr <<
"You must use the -b option to specify the private key output filenames.\n";
407 for (
int i = 1; i < argc; i++) {
410 key._number = (int)strtol(argv[i], &endptr, 0);
411 key._got_pass_phrase = got_pass_phrase;
412 key._pass_phrase = pass_phrase;
414 if (*endptr ==
',') {
416 key._got_pass_phrase =
true;
417 key._pass_phrase = endptr + 1;
418 }
else if (*endptr) {
419 cerr <<
"Parameter '" << argv[i] <<
"' should be an integer.\n";
422 if (key._number <= 0) {
423 cerr <<
"Key numbers must be greater than 0; you specified "
424 << key._number <<
".\n";
427 key_numbers.push_back(key);
434 OpenSSL_add_all_algorithms();
436 time_t now = time(
nullptr);
439 string prefix, suffix;
442 size_t hash = name.find(
'#');
443 if (hash == string::npos) {
449 prefix = name.substr(0, hash);
450 suffix = name.substr(hash + 1) +
".cxx";
454 KeyNumbers::iterator ki;
455 for (ki = key_numbers.begin(); ki != key_numbers.end(); ++ki) {
456 int n = (*ki)._number;
457 const char *pp =
nullptr;
458 if ((*ki)._got_pass_phrase) {
459 pp = (*ki)._pass_phrase.c_str();
463 PrcKeyRegistry::get_global_ptr()->set_key(n, pkey, now);
465 std::ostringstream strm;
466 if (got_hash || n != 1) {
470 strm << prefix << n << suffix;
476 strm << prefix << suffix;
The name of a file, such as a texture file or an Egg file.
std::string get_fullpath_wo_extension() const
Returns the full filename–directory and basename parts–except for the extension.
void set_text()
Indicates that the filename represents a text file.
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
std::string get_extension() const
Returns the file extension.
std::string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
EVP_PKEY * generate_key()
Generates a new public and private key pair.
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...
void write_public_keys(Filename outfile)
Writes the list of public keys stored in the PrcKeyRegistry to the indicated output filename as a com...
void output_ssl_errors()
A convenience function that is itself a wrapper around the OpenSSL convenience function to output the...
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,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.