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);
251 #define MIN_PASSPHRASE_LEN 4
258 load_identity_key(
void)
266 if (status != FN_NOENT) {
267 log_err(
LD_GENERAL,
"--create-identity-key was specified, but %s "
268 "already exists.", identity_key_file);
271 log_notice(
LD_GENERAL,
"Generating %d-bit RSA identity key.",
273 if (!(key = generate_key(IDENTITY_KEY_BITS))) {
274 log_err(
LD_GENERAL,
"Couldn't generate identity key.");
278 identity_key = EVP_PKEY_new();
279 if (!(EVP_PKEY_assign_RSA(identity_key, key))) {
280 log_err(
LD_GENERAL,
"Couldn't assign identity key.");
285 OPEN_FLAGS_REPLACE | O_TEXT, 0400,
291 if (!PEM_write_PKCS8PrivateKey_nid(f, identity_key,
292 NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
293 passphrase, (
int) passphrase_len,
295 if ((
int) passphrase_len < MIN_PASSPHRASE_LEN) {
296 log_err(
LD_GENERAL,
"Passphrase empty or too short. Passphrase needs "
297 "to be at least %d characters.", MIN_PASSPHRASE_LEN);
299 log_err(
LD_GENERAL,
"Couldn't write identity key to %s",
308 if (status != FN_FILE) {
310 "No identity key found in %s. To specify a location "
311 "for an identity key, use -i. To generate a new identity key, "
312 "use --create-identity-key.", identity_key_file);
316 if (!(f = fopen(identity_key_file,
"r"))) {
317 log_err(
LD_GENERAL,
"Couldn't open %s for reading: %s",
318 identity_key_file, strerror(errno));
323 identity_key = PEM_read_PrivateKey(f, NULL, NULL, passphrase);
325 log_err(
LD_GENERAL,
"Couldn't read identity key from %s",
338 load_signing_key(
void)
341 if (!(f = fopen(signing_key_file,
"r"))) {
342 log_err(
LD_GENERAL,
"Couldn't open %s for reading: %s",
343 signing_key_file, strerror(errno));
346 if (!(signing_key = PEM_read_PrivateKey(f, NULL, NULL, NULL))) {
347 log_err(
LD_GENERAL,
"Couldn't read siging key from %s", signing_key_file);
358 generate_signing_key(
void)
363 log_notice(
LD_GENERAL,
"Generating %d-bit RSA signing key.",
365 if (!(key = generate_key(SIGNING_KEY_BITS))) {
366 log_err(
LD_GENERAL,
"Couldn't generate signing key.");
370 signing_key = EVP_PKEY_new();
371 if (!(EVP_PKEY_assign_RSA(signing_key, key))) {
372 log_err(
LD_GENERAL,
"Couldn't assign signing key.");
377 OPEN_FLAGS_REPLACE | O_TEXT, 0600,
382 if (!PEM_write_RSAPrivateKey(f, key, NULL, NULL, 0, NULL, NULL)) {
396 key_to_string(EVP_PKEY *key)
400 RSA *rsa = EVP_PKEY_get1_RSA(key);
405 b = BIO_new(BIO_s_mem());
406 if (!PEM_write_bio_RSAPublicKey(b, rsa)) {
412 BIO_get_mem_ptr(b, &buf);
413 result = tor_malloc(buf->length + 1);
414 memcpy(result, buf->data, buf->length);
415 result[buf->length] = 0;
425 get_fingerprint(EVP_PKEY *pkey,
char *out)
428 crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(EVP_PKEY_get1_RSA(pkey));
438 get_digest(EVP_PKEY *pkey,
char *out)
441 crypto_pk_t *pk = crypto_new_pk_from_openssl_rsa_(EVP_PKEY_get1_RSA(pkey));
452 generate_certificate(
void)
455 time_t now = time(NULL);
457 char published[ISO_TIME_LEN+1];
458 char expires[ISO_TIME_LEN+1];
464 char signature[1024];
467 if (get_fingerprint(identity_key, fingerprint) < 0) {
470 if (get_digest(identity_key, id_digest)) {
473 char *ident = key_to_string(identity_key);
474 char *signing = key_to_string(signing_key);
477 tm.tm_mon += months_lifetime;
483 "dir-key-certificate-version 3"
486 "dir-key-published %s\n"
487 "dir-key-expires %s\n"
488 "dir-identity-key\n%s"
489 "dir-signing-key\n%s"
490 "dir-key-crosscert\n"
491 "-----BEGIN ID SIGNATURE-----\n",
492 address?
"\ndir-address ":
"", address?address:
"",
493 fingerprint, published, expires, ident, signing
499 RSA *rsa = EVP_PKEY_get1_RSA(signing_key);
500 r = RSA_private_encrypt(
DIGEST_LEN, (
unsigned char*)id_digest,
501 (
unsigned char*)signature,
506 signed_len = strlen(buf);
507 base64_encode(buf+signed_len,
sizeof(buf)-signed_len, signature, r,
508 BASE64_ENCODE_MULTILINE);
511 "-----END ID SIGNATURE-----\n"
512 "dir-key-certification\n",
sizeof(buf));
514 signed_len = strlen(buf);
515 SHA1((
const unsigned char*)buf,signed_len,(
unsigned char*)digest);
517 rsa = EVP_PKEY_get1_RSA(identity_key);
518 r = RSA_private_encrypt(
DIGEST_LEN, (
unsigned char*)digest,
519 (
unsigned char*)signature,
523 strlcat(buf,
"-----BEGIN SIGNATURE-----\n",
sizeof(buf));
524 signed_len = strlen(buf);
525 base64_encode(buf+signed_len,
sizeof(buf)-signed_len, signature, r,
526 BASE64_ENCODE_MULTILINE);
527 strlcat(buf,
"-----END SIGNATURE-----\n",
sizeof(buf));
529 if (!(f = fopen(certificate_file,
"w"))) {
530 log_err(
LD_GENERAL,
"Couldn't open %s for writing: %s",
531 certificate_file, strerror(errno));
535 if (fputs(buf, f) < 0) {
536 log_err(
LD_GENERAL,
"Couldn't write to %s: %s",
537 certificate_file, strerror(errno));
547 main(
int argc,
char **argv)
554 fprintf(stderr,
"Couldn't initialize crypto library.\n");
558 fprintf(stderr,
"Couldn't seed RNG.\n");
564 if (parse_commandline(argc, argv))
566 if (load_identity_key())
568 if (reuse_signing_key) {
569 if (load_signing_key())
572 if (generate_signing_key())
575 if (generate_certificate())
582 EVP_PKEY_free(identity_key);
584 EVP_PKEY_free(signing_key);
const char * fmt_addrport(const tor_addr_t *addr, uint16_t port)
static sa_family_t tor_addr_family(const tor_addr_t *a)
int base64_encode(char *dest, size_t destlen, const char *src, size_t srclen, int flags)
Utility macros to handle different features and behavior in different compilers.
Header for compat_string.c.
Headers for crypto_digest.c.
int crypto_global_cleanup(void)
int crypto_global_init(int useAccel, const char *accelName, const char *accelDir)
Headers for crypto_init.c.
void crypto_openssl_log_errors(int severity, const char *doing)
Headers for crypto_openssl_mgt.c.
int crypto_seed_rng(void)
Common functions for using (pseudo-)random number generators.
int crypto_pk_get_fingerprint(crypto_pk_t *pk, char *fp_out, int add_space)
int crypto_pk_get_digest(const crypto_pk_t *pk, char *digest_out)
Headers for crypto_rsa.c.
int crypto_pk_generate_key_with_bits(crypto_pk_t *env, int bits)
crypto_pk_t * crypto_pk_new(void)
void memwipe(void *mem, uint8_t byte, size_t sz)
Common functions for cryptographic routines.
Wrappers for reading and writing data to files on disk.
ssize_t read_all_from_fd(int fd, char *buf, size_t count)
file_status_t file_status(const char *filename)
int finish_writing_to_file(open_file_t *file_data)
FILE * start_writing_to_stdio_file(const char *fname, int open_flags, int mode, open_file_t **data_out)
int abort_writing_to_file(open_file_t *file_data)
void init_logging(int disable_startup_queue)
void set_log_severity_config(int loglevelMin, int loglevelMax, log_severity_list_t *severity_out)
void add_stream_log(const log_severity_list_t *severity, const char *name, int fd)
Headers for util_malloc.c.
int tor_snprintf(char *str, size_t size, const char *format,...)
int tor_addr_port_lookup(const char *s, tor_addr_t *addr_out, uint16_t *port_out)
void format_iso_time(char *buf, time_t t)
struct tm * tor_localtime_r(const time_t *timep, struct tm *result)
int main(int argc, char *argv[])