24 DISABLE_GCC_WARNING(
"-Wredundant-decls")
26 #include <openssl/evp.h>
27 #include <openssl/pem.h>
28 #include <openssl/rsa.h>
29 #include <openssl/objects.h>
30 #include <openssl/obj_mac.h>
31 #include <openssl/err.h>
33 ENABLE_GCC_WARNING(
"-Wredundant-decls")
53 #define IDENTITY_KEY_BITS 3072
54 #define SIGNING_KEY_BITS 2048
55 #define DEFAULT_LIFETIME 12
58 static char *identity_key_file = NULL;
59 static char *signing_key_file = NULL;
60 static char *certificate_file = NULL;
61 static int reuse_signing_key = 0;
62 static int verbose = 0;
63 static int make_new_id = 0;
64 static int months_lifetime = DEFAULT_LIFETIME;
65 static int passphrase_fd = -1;
66 static char *address = NULL;
68 static char *passphrase = NULL;
69 static size_t passphrase_len = 0;
71 static EVP_PKEY *identity_key = NULL;
72 static EVP_PKEY *signing_key = NULL;
78 fprintf(stderr,
"Syntax:\n"
79 "tor-gencert [-h|--help] [-v] [-r|--reuse] [--create-identity-key]\n"
80 " [-i identity_key_file] [-s signing_key_file] "
81 "[-c certificate_file]\n"
82 " [-m lifetime_in_months] [-a address:port] "
83 "[--passphrase-fd <fd>]\n");
92 memset(buf, 0,
sizeof(buf));
95 log_err(
LD_GENERAL,
"Couldn't read from passphrase fd: %s",
101 cp = memchr(buf,
'\n', n);
105 passphrase_len = cp-buf;
107 passphrase = tor_strndup(buf, passphrase_len);
113 clear_passphrase(
void)
116 memwipe(passphrase, 0, passphrase_len);
125 parse_commandline(
int argc,
char **argv)
129 for (i = 1; i < argc; ++i) {
130 if (!strcmp(argv[i],
"--help") || !strcmp(argv[i],
"-h")) {
133 }
else if (!strcmp(argv[i],
"-i")) {
135 fprintf(stderr,
"No argument to -i\n");
138 if (identity_key_file) {
139 fprintf(stderr,
"Duplicate values for -i\n");
142 identity_key_file = tor_strdup(argv[++i]);
143 }
else if (!strcmp(argv[i],
"-s")) {
145 fprintf(stderr,
"No argument to -s\n");
148 if (signing_key_file) {
149 fprintf(stderr,
"Duplicate values for -s\n");
152 signing_key_file = tor_strdup(argv[++i]);
153 }
else if (!strcmp(argv[i],
"-c")) {
155 fprintf(stderr,
"No argument to -c\n");
158 if (certificate_file) {
159 fprintf(stderr,
"Duplicate values for -c\n");
162 certificate_file = tor_strdup(argv[++i]);
163 }
else if (!strcmp(argv[i],
"-m")) {
165 fprintf(stderr,
"No argument to -m\n");
168 months_lifetime = atoi(argv[++i]);
169 if (months_lifetime > 24 || months_lifetime < 0) {
170 fprintf(stderr,
"Lifetime (in months) was out of range.\n");
173 }
else if (!strcmp(argv[i],
"-r") || !strcmp(argv[i],
"--reuse")) {
174 reuse_signing_key = 1;
175 }
else if (!strcmp(argv[i],
"-v")) {
177 }
else if (!strcmp(argv[i],
"-a")) {
181 fprintf(stderr,
"No argument to -a\n");
184 const char *addr_arg = argv[++i];
186 fprintf(stderr,
"Can't resolve address/port for %s", addr_arg);
190 fprintf(stderr,
"%s must resolve to an IPv4 address", addr_arg);
195 }
else if (!strcmp(argv[i],
"--create-identity-key")) {
197 }
else if (!strcmp(argv[i],
"--passphrase-fd")) {
199 fprintf(stderr,
"No argument to --passphrase-fd\n");
202 passphrase_fd = atoi(argv[++i]);
204 fprintf(stderr,
"Unrecognized option %s\n", argv[i]);
216 if (!identity_key_file) {
217 identity_key_file = tor_strdup(
"./authority_identity_key");
218 log_info(
LD_GENERAL,
"No identity key file given; defaulting to %s",
221 if (!signing_key_file) {
222 signing_key_file = tor_strdup(
"./authority_signing_key");
223 log_info(
LD_GENERAL,
"No signing key file given; defaulting to %s",
226 if (!certificate_file) {
227 certificate_file = tor_strdup(
"./authority_certificate");
228 log_info(
LD_GENERAL,
"No signing key file given; defaulting to %s",
231 if (passphrase_fd >= 0) {
232 if (load_passphrase()<0)
239 generate_key(
int bits)
245 rsa = crypto_pk_get_openssl_rsa_(env);
256 load_identity_key(
void)
264 if (status != FN_NOENT) {
265 log_err(
LD_GENERAL,
"--create-identity-key was specified, but %s "
266 "already exists.", identity_key_file);
269 log_notice(
LD_GENERAL,
"Generating %d-bit RSA identity key.",
271 if (!(key = generate_key(IDENTITY_KEY_BITS))) {
272 log_err(
LD_GENERAL,
"Couldn't generate identity key.");
276 identity_key = EVP_PKEY_new();
277 if (!(EVP_PKEY_assign_RSA(identity_key, key))) {
278 log_err(
LD_GENERAL,
"Couldn't assign identity key.");
283 OPEN_FLAGS_REPLACE | O_TEXT, 0400,
289 if (!PEM_write_PKCS8PrivateKey_nid(f, identity_key,
290 NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
291 passphrase, (
int)passphrase_len,
293 log_err(
LD_GENERAL,
"Couldn't write identity key to %s",
301 if (status != FN_FILE) {
303 "No identity key found in %s. To specify a location "
304 "for an identity key, use -i. To generate a new identity key, "
305 "use --create-identity-key.", identity_key_file);
309 if (!(f = fopen(identity_key_file,
"r"))) {
310 log_err(
LD_GENERAL,
"Couldn't open %s for reading: %s",
311 identity_key_file, strerror(errno));
316 identity_key = PEM_read_PrivateKey(f, NULL, NULL, passphrase);
318 log_err(
LD_GENERAL,
"Couldn't read identity key from %s",
331 load_signing_key(
void)
334 if (!(f = fopen(signing_key_file,
"r"))) {
335 log_err(
LD_GENERAL,
"Couldn't open %s for reading: %s",
336 signing_key_file, strerror(errno));
339 if (!(signing_key = PEM_read_PrivateKey(f, NULL, NULL, NULL))) {
340 log_err(
LD_GENERAL,
"Couldn't read siging key from %s", signing_key_file);
351 generate_signing_key(
void)
356 log_notice(
LD_GENERAL,
"Generating %d-bit RSA signing key.",
358 if (!(key = generate_key(SIGNING_KEY_BITS))) {
359 log_err(
LD_GENERAL,
"Couldn't generate signing key.");
363 signing_key = EVP_PKEY_new();
364 if (!(EVP_PKEY_assign_RSA(signing_key, key))) {
365 log_err(
LD_GENERAL,
"Couldn't assign signing key.");
370 OPEN_FLAGS_REPLACE | O_TEXT, 0600,
375 if (!PEM_write_RSAPrivateKey(f, key, NULL, NULL, 0, NULL, NULL)) {
389 key_to_string(EVP_PKEY *key)
393 RSA *rsa = EVP_PKEY_get1_RSA(key);
398 b = BIO_new(BIO_s_mem());
399 if (!PEM_write_bio_RSAPublicKey(b, rsa)) {
405 BIO_get_mem_ptr(b, &buf);
406 result = tor_malloc(buf->length + 1);
407 memcpy(result, buf->data, buf->length);
408 result[buf->length] = 0;
418 get_fingerprint(EVP_PKEY *pkey,
char *out)
421 crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(EVP_PKEY_get1_RSA(pkey));
431 get_digest(EVP_PKEY *pkey,
char *out)
434 crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(EVP_PKEY_get1_RSA(pkey));
445 generate_certificate(
void)
448 time_t now = time(NULL);
450 char published[ISO_TIME_LEN+1];
451 char expires[ISO_TIME_LEN+1];
457 char signature[1024];
460 if (get_fingerprint(identity_key, fingerprint) < 0) {
463 if (get_digest(identity_key, id_digest)) {
466 char *ident = key_to_string(identity_key);
467 char *signing = key_to_string(signing_key);
470 tm.tm_mon += months_lifetime;
476 "dir-key-certificate-version 3"
479 "dir-key-published %s\n"
480 "dir-key-expires %s\n"
481 "dir-identity-key\n%s"
482 "dir-signing-key\n%s"
483 "dir-key-crosscert\n"
484 "-----BEGIN ID SIGNATURE-----\n",
485 address?
"\ndir-address ":
"", address?address:
"",
486 fingerprint, published, expires, ident, signing
492 RSA *rsa = EVP_PKEY_get1_RSA(signing_key);
493 r = RSA_private_encrypt(
DIGEST_LEN, (
unsigned char*)id_digest,
494 (
unsigned char*)signature,
499 signed_len = strlen(buf);
500 base64_encode(buf+signed_len,
sizeof(buf)-signed_len, signature, r,
501 BASE64_ENCODE_MULTILINE);
504 "-----END ID SIGNATURE-----\n"
505 "dir-key-certification\n",
sizeof(buf));
507 signed_len = strlen(buf);
508 SHA1((
const unsigned char*)buf,signed_len,(
unsigned char*)digest);
510 rsa = EVP_PKEY_get1_RSA(identity_key);
511 r = RSA_private_encrypt(
DIGEST_LEN, (
unsigned char*)digest,
512 (
unsigned char*)signature,
516 strlcat(buf,
"-----BEGIN SIGNATURE-----\n",
sizeof(buf));
517 signed_len = strlen(buf);
518 base64_encode(buf+signed_len,
sizeof(buf)-signed_len, signature, r,
519 BASE64_ENCODE_MULTILINE);
520 strlcat(buf,
"-----END SIGNATURE-----\n",
sizeof(buf));
522 if (!(f = fopen(certificate_file,
"w"))) {
523 log_err(
LD_GENERAL,
"Couldn't open %s for writing: %s",
524 certificate_file, strerror(errno));
528 if (fputs(buf, f) < 0) {
529 log_err(
LD_GENERAL,
"Couldn't write to %s: %s",
530 certificate_file, strerror(errno));
540 main(
int argc,
char **argv)
547 fprintf(stderr,
"Couldn't initialize crypto library.\n");
551 fprintf(stderr,
"Couldn't seed RNG.\n");
557 if (parse_commandline(argc, argv))
559 if (load_identity_key())
561 if (reuse_signing_key) {
562 if (load_signing_key())
565 if (generate_signing_key())
568 if (generate_certificate())
575 EVP_PKEY_free(identity_key);
577 EVP_PKEY_free(signing_key);