Back to index

tor  0.2.3.18-rc
tor-gencert.c
Go to the documentation of this file.
00001 /* Copyright (c) 2007-2012, The Tor Project, Inc. */
00002 /* See LICENSE for licensing information */
00003 
00004 #include "orconfig.h"
00005 
00006 #include <stdio.h>
00007 #include <string.h>
00008 
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <fcntl.h>
00012 #ifdef HAVE_UNISTD_H
00013 #include <unistd.h>
00014 #endif
00015 
00016 #include <openssl/evp.h>
00017 #include <openssl/pem.h>
00018 #include <openssl/rsa.h>
00019 #include <openssl/objects.h>
00020 #include <openssl/obj_mac.h>
00021 #include <openssl/err.h>
00022 
00023 #include <errno.h>
00024 #if 0
00025 #include <stdlib.h>
00026 #include <stdarg.h>
00027 #include <assert.h>
00028 #endif
00029 
00030 #define CRYPTO_PRIVATE
00031 
00032 #include "compat.h"
00033 #include "../common/util.h"
00034 #include "../common/torlog.h"
00035 #include "crypto.h"
00036 #include "address.h"
00037 
00038 #define IDENTITY_KEY_BITS 3072
00039 #define SIGNING_KEY_BITS 1024
00040 #define DEFAULT_LIFETIME 12
00041 
00042 /* These globals are set via command line options. */
00043 char *identity_key_file = NULL;
00044 char *signing_key_file = NULL;
00045 char *certificate_file = NULL;
00046 int reuse_signing_key = 0;
00047 int verbose = 0;
00048 int make_new_id = 0;
00049 int months_lifetime = DEFAULT_LIFETIME;
00050 int passphrase_fd = -1;
00051 char *address = NULL;
00052 
00053 char *passphrase = NULL;
00054 size_t passphrase_len = 0;
00055 
00056 EVP_PKEY *identity_key = NULL;
00057 EVP_PKEY *signing_key = NULL;
00058 
00060 static void
00061 show_help(void)
00062 {
00063   fprintf(stderr, "Syntax:\n"
00064           "tor-gencert [-h|--help] [-v] [-r|--reuse] [--create-identity-key]\n"
00065           "        [-i identity_key_file] [-s signing_key_file] "
00066           "[-c certificate_file]\n"
00067           "        [-m lifetime_in_months] [-a address:port] "
00068           "[--passphrase-fd <fd>]\n");
00069 }
00070 
00071 /* XXXX copied from crypto.c */
00072 static void
00073 crypto_log_errors(int severity, const char *doing)
00074 {
00075   unsigned long err;
00076   const char *msg, *lib, *func;
00077   while ((err = ERR_get_error()) != 0) {
00078     msg = (const char*)ERR_reason_error_string(err);
00079     lib = (const char*)ERR_lib_error_string(err);
00080     func = (const char*)ERR_func_error_string(err);
00081     if (!msg) msg = "(null)";
00082     if (!lib) lib = "(null)";
00083     if (!func) func = "(null)";
00084     if (doing) {
00085       log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)",
00086           doing, msg, lib, func);
00087     } else {
00088       log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", msg, lib, func);
00089     }
00090   }
00091 }
00092 
00094 static int
00095 load_passphrase(void)
00096 {
00097   char *cp;
00098   char buf[1024]; /* "Ought to be enough for anybody." */
00099   ssize_t n = read_all(passphrase_fd, buf, sizeof(buf), 0);
00100   if (n < 0) {
00101     log_err(LD_GENERAL, "Couldn't read from passphrase fd: %s",
00102             strerror(errno));
00103     return -1;
00104   }
00105   cp = memchr(buf, '\n', n);
00106   passphrase_len = cp-buf;
00107   passphrase = tor_strndup(buf, passphrase_len);
00108   memset(buf, 0, sizeof(buf));
00109   return 0;
00110 }
00111 
00112 static void
00113 clear_passphrase(void)
00114 {
00115   if (passphrase) {
00116     memset(passphrase, 0, passphrase_len);
00117     tor_free(passphrase);
00118   }
00119 }
00120 
00124 static int
00125 parse_commandline(int argc, char **argv)
00126 {
00127   int i;
00128   log_severity_list_t s;
00129   for (i = 1; i < argc; ++i) {
00130     if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) {
00131       show_help();
00132       return 1;
00133     } else if (!strcmp(argv[i], "-i")) {
00134       if (i+1>=argc) {
00135         fprintf(stderr, "No argument to -i\n");
00136         return 1;
00137       }
00138       identity_key_file = tor_strdup(argv[++i]);
00139     } else if (!strcmp(argv[i], "-s")) {
00140       if (i+1>=argc) {
00141         fprintf(stderr, "No argument to -s\n");
00142         return 1;
00143       }
00144       signing_key_file = tor_strdup(argv[++i]);
00145     } else if (!strcmp(argv[i], "-c")) {
00146       if (i+1>=argc) {
00147         fprintf(stderr, "No argument to -c\n");
00148         return 1;
00149       }
00150       certificate_file = tor_strdup(argv[++i]);
00151     } else if (!strcmp(argv[i], "-m")) {
00152       if (i+1>=argc) {
00153         fprintf(stderr, "No argument to -m\n");
00154         return 1;
00155       }
00156       months_lifetime = atoi(argv[++i]);
00157       if (months_lifetime > 24 || months_lifetime < 0) {
00158         fprintf(stderr, "Lifetime (in months) was out of range.\n");
00159         return 1;
00160       }
00161     } else if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--reuse")) {
00162       reuse_signing_key = 1;
00163     } else if (!strcmp(argv[i], "-v")) {
00164       verbose = 1;
00165     } else if (!strcmp(argv[i], "-a")) {
00166       uint32_t addr;
00167       uint16_t port;
00168       char b[INET_NTOA_BUF_LEN];
00169       struct in_addr in;
00170       if (i+1>=argc) {
00171         fprintf(stderr, "No argument to -a\n");
00172         return 1;
00173       }
00174       if (addr_port_lookup(LOG_ERR, argv[++i], NULL, &addr, &port)<0)
00175         return 1;
00176       in.s_addr = htonl(addr);
00177       tor_inet_ntoa(&in, b, sizeof(b));
00178       address = tor_malloc(INET_NTOA_BUF_LEN+32);
00179       tor_snprintf(address, INET_NTOA_BUF_LEN+32, "%s:%d", b, (int)port);
00180     } else if (!strcmp(argv[i], "--create-identity-key")) {
00181       make_new_id = 1;
00182     } else if (!strcmp(argv[i], "--passphrase-fd")) {
00183       if (i+1>=argc) {
00184         fprintf(stderr, "No argument to --passphrase-fd\n");
00185         return 1;
00186       }
00187       passphrase_fd = atoi(argv[++i]);
00188     } else {
00189       fprintf(stderr, "Unrecognized option %s\n", argv[i]);
00190       return 1;
00191     }
00192   }
00193 
00194   memset(&s, 0, sizeof(s));
00195   if (verbose)
00196     set_log_severity_config(LOG_DEBUG, LOG_ERR, &s);
00197   else
00198     set_log_severity_config(LOG_WARN, LOG_ERR, &s);
00199   add_stream_log(&s, "<stderr>", fileno(stderr));
00200 
00201   if (!identity_key_file) {
00202     identity_key_file = tor_strdup("./authority_identity_key");
00203     log_info(LD_GENERAL, "No identity key file given; defaulting to %s",
00204              identity_key_file);
00205   }
00206   if (!signing_key_file) {
00207     signing_key_file = tor_strdup("./authority_signing_key");
00208     log_info(LD_GENERAL, "No signing key file given; defaulting to %s",
00209              signing_key_file);
00210   }
00211   if (!certificate_file) {
00212     certificate_file = tor_strdup("./authority_certificate");
00213     log_info(LD_GENERAL, "No signing key file given; defaulting to %s",
00214              certificate_file);
00215   }
00216   if (passphrase_fd >= 0) {
00217     if (load_passphrase()<0)
00218       return 1;
00219   }
00220   return 0;
00221 }
00222 
00223 static RSA *
00224 generate_key(int bits)
00225 {
00226   RSA *rsa = NULL;
00227   crypto_pk_t *env = crypto_pk_new();
00228   if (crypto_pk_generate_key_with_bits(env,bits)<0)
00229     goto done;
00230   rsa = _crypto_pk_get_rsa(env);
00231   rsa = RSAPrivateKey_dup(rsa);
00232  done:
00233   crypto_pk_free(env);
00234   return rsa;
00235 }
00236 
00241 static int
00242 load_identity_key(void)
00243 {
00244   file_status_t status = file_status(identity_key_file);
00245   FILE *f;
00246 
00247   if (make_new_id) {
00248     open_file_t *open_file = NULL;
00249     RSA *key;
00250     if (status != FN_NOENT) {
00251       log_err(LD_GENERAL, "--create-identity-key was specified, but %s "
00252               "already exists.", identity_key_file);
00253       return 1;
00254     }
00255     log_notice(LD_GENERAL, "Generating %d-bit RSA identity key.",
00256                IDENTITY_KEY_BITS);
00257     if (!(key = generate_key(IDENTITY_KEY_BITS))) {
00258       log_err(LD_GENERAL, "Couldn't generate identity key.");
00259       crypto_log_errors(LOG_ERR, "Generating identity key");
00260       return 1;
00261     }
00262     identity_key = EVP_PKEY_new();
00263     if (!(EVP_PKEY_assign_RSA(identity_key, key))) {
00264       log_err(LD_GENERAL, "Couldn't assign identity key.");
00265       return 1;
00266     }
00267 
00268     if (!(f = start_writing_to_stdio_file(identity_key_file,
00269                                           OPEN_FLAGS_REPLACE | O_TEXT, 0400,
00270                                           &open_file)))
00271       return 1;
00272 
00273     /* Write the key to the file.  If passphrase is not set, takes it from
00274      * the terminal. */
00275     if (!PEM_write_PKCS8PrivateKey_nid(f, identity_key,
00276                                        NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
00277                                        passphrase, (int)passphrase_len,
00278                                        NULL, NULL)) {
00279       log_err(LD_GENERAL, "Couldn't write identity key to %s",
00280               identity_key_file);
00281       crypto_log_errors(LOG_ERR, "Writing identity key");
00282       abort_writing_to_file(open_file);
00283       return 1;
00284     }
00285     finish_writing_to_file(open_file);
00286   } else {
00287     if (status != FN_FILE) {
00288       log_err(LD_GENERAL,
00289               "No identity key found in %s.  To specify a location "
00290               "for an identity key, use -i.  To generate a new identity key, "
00291               "use --create-identity-key.", identity_key_file);
00292       return 1;
00293     }
00294 
00295     if (!(f = fopen(identity_key_file, "r"))) {
00296       log_err(LD_GENERAL, "Couldn't open %s for reading: %s",
00297               identity_key_file, strerror(errno));
00298       return 1;
00299     }
00300 
00301     /* Read the key.  If passphrase is not set, takes it from the terminal. */
00302     identity_key = PEM_read_PrivateKey(f, NULL, NULL, passphrase);
00303     if (!identity_key) {
00304       log_err(LD_GENERAL, "Couldn't read identity key from %s",
00305               identity_key_file);
00306       return 1;
00307     }
00308     fclose(f);
00309   }
00310   return 0;
00311 }
00312 
00315 static int
00316 load_signing_key(void)
00317 {
00318   FILE *f;
00319   if (!(f = fopen(signing_key_file, "r"))) {
00320     log_err(LD_GENERAL, "Couldn't open %s for reading: %s",
00321             signing_key_file, strerror(errno));
00322     return 1;
00323   }
00324   if (!(signing_key = PEM_read_PrivateKey(f, NULL, NULL, NULL))) {
00325     log_err(LD_GENERAL, "Couldn't read siging key from %s", signing_key_file);
00326     return 1;
00327   }
00328   fclose(f);
00329   return 0;
00330 }
00331 
00334 static int
00335 generate_signing_key(void)
00336 {
00337   open_file_t *open_file;
00338   FILE *f;
00339   RSA *key;
00340   log_notice(LD_GENERAL, "Generating %d-bit RSA signing key.",
00341              SIGNING_KEY_BITS);
00342   if (!(key = generate_key(SIGNING_KEY_BITS))) {
00343     log_err(LD_GENERAL, "Couldn't generate signing key.");
00344     crypto_log_errors(LOG_ERR, "Generating signing key");
00345     return 1;
00346   }
00347   signing_key = EVP_PKEY_new();
00348   if (!(EVP_PKEY_assign_RSA(signing_key, key))) {
00349     log_err(LD_GENERAL, "Couldn't assign signing key.");
00350     return 1;
00351   }
00352 
00353   if (!(f = start_writing_to_stdio_file(signing_key_file,
00354                                         OPEN_FLAGS_REPLACE | O_TEXT, 0600,
00355                                         &open_file)))
00356     return 1;
00357 
00358   /* Write signing key with no encryption. */
00359   if (!PEM_write_RSAPrivateKey(f, key, NULL, NULL, 0, NULL, NULL)) {
00360     crypto_log_errors(LOG_WARN, "writing signing key");
00361     abort_writing_to_file(open_file);
00362     return 1;
00363   }
00364 
00365   finish_writing_to_file(open_file);
00366 
00367   return 0;
00368 }
00369 
00372 static char *
00373 key_to_string(EVP_PKEY *key)
00374 {
00375   BUF_MEM *buf;
00376   BIO *b;
00377   RSA *rsa = EVP_PKEY_get1_RSA(key);
00378   char *result;
00379   if (!rsa)
00380     return NULL;
00381 
00382   b = BIO_new(BIO_s_mem());
00383   if (!PEM_write_bio_RSAPublicKey(b, rsa)) {
00384     crypto_log_errors(LOG_WARN, "writing public key to string");
00385     return NULL;
00386   }
00387 
00388   BIO_get_mem_ptr(b, &buf);
00389   (void) BIO_set_close(b, BIO_NOCLOSE);
00390   BIO_free(b);
00391   result = tor_malloc(buf->length + 1);
00392   memcpy(result, buf->data, buf->length);
00393   result[buf->length] = 0;
00394   BUF_MEM_free(buf);
00395 
00396   return result;
00397 }
00398 
00400 static int
00401 get_fingerprint(EVP_PKEY *pkey, char *out)
00402 {
00403   int r = 1;
00404   crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
00405   if (pk) {
00406     r = crypto_pk_get_fingerprint(pk, out, 0);
00407     crypto_pk_free(pk);
00408   }
00409   return r;
00410 }
00411 
00413 static int
00414 get_digest(EVP_PKEY *pkey, char *out)
00415 {
00416   int r = 1;
00417   crypto_pk_t *pk = _crypto_new_pk_from_rsa(EVP_PKEY_get1_RSA(pkey));
00418   if (pk) {
00419     r = crypto_pk_get_digest(pk, out);
00420     crypto_pk_free(pk);
00421   }
00422   return r;
00423 }
00424 
00427 static int
00428 generate_certificate(void)
00429 {
00430   char buf[8192];
00431   time_t now = time(NULL);
00432   struct tm tm;
00433   char published[ISO_TIME_LEN+1];
00434   char expires[ISO_TIME_LEN+1];
00435   char id_digest[DIGEST_LEN];
00436   char fingerprint[FINGERPRINT_LEN+1];
00437   char *ident = key_to_string(identity_key);
00438   char *signing = key_to_string(signing_key);
00439   FILE *f;
00440   size_t signed_len;
00441   char digest[DIGEST_LEN];
00442   char signature[1024]; /* handles up to 8192-bit keys. */
00443   int r;
00444 
00445   get_fingerprint(identity_key, fingerprint);
00446   get_digest(identity_key, id_digest);
00447 
00448   tor_localtime_r(&now, &tm);
00449   tm.tm_mon += months_lifetime;
00450 
00451   format_iso_time(published, now);
00452   format_iso_time(expires, mktime(&tm));
00453 
00454   tor_snprintf(buf, sizeof(buf),
00455                "dir-key-certificate-version 3"
00456                "%s%s"
00457                "\nfingerprint %s\n"
00458                "dir-key-published %s\n"
00459                "dir-key-expires %s\n"
00460                "dir-identity-key\n%s"
00461                "dir-signing-key\n%s"
00462                "dir-key-crosscert\n"
00463                "-----BEGIN ID SIGNATURE-----\n",
00464                address?"\ndir-address ":"", address?address:"",
00465                fingerprint, published, expires, ident, signing
00466                );
00467   tor_free(ident);
00468   tor_free(signing);
00469 
00470   /* Append a cross-certification */
00471   r = RSA_private_encrypt(DIGEST_LEN, (unsigned char*)id_digest,
00472                           (unsigned char*)signature,
00473                           EVP_PKEY_get1_RSA(signing_key),
00474                           RSA_PKCS1_PADDING);
00475   signed_len = strlen(buf);
00476   base64_encode(buf+signed_len, sizeof(buf)-signed_len, signature, r);
00477 
00478   strlcat(buf,
00479           "-----END ID SIGNATURE-----\n"
00480           "dir-key-certification\n", sizeof(buf));
00481 
00482   signed_len = strlen(buf);
00483   SHA1((const unsigned char*)buf,signed_len,(unsigned char*)digest);
00484 
00485   r = RSA_private_encrypt(DIGEST_LEN, (unsigned char*)digest,
00486                           (unsigned char*)signature,
00487                           EVP_PKEY_get1_RSA(identity_key),
00488                           RSA_PKCS1_PADDING);
00489   strlcat(buf, "-----BEGIN SIGNATURE-----\n", sizeof(buf));
00490   signed_len = strlen(buf);
00491   base64_encode(buf+signed_len, sizeof(buf)-signed_len, signature, r);
00492   strlcat(buf, "-----END SIGNATURE-----\n", sizeof(buf));
00493 
00494   if (!(f = fopen(certificate_file, "w"))) {
00495     log_err(LD_GENERAL, "Couldn't open %s for writing: %s",
00496             certificate_file, strerror(errno));
00497     return 1;
00498   }
00499 
00500   fputs(buf, f);
00501   fclose(f);
00502   return 0;
00503 }
00504 
00506 int
00507 main(int argc, char **argv)
00508 {
00509   int r = 1;
00510   init_logging();
00511 
00512   /* Don't bother using acceleration. */
00513   if (crypto_global_init(0, NULL, NULL)) {
00514     fprintf(stderr, "Couldn't initialize crypto library.\n");
00515     return 1;
00516   }
00517   if (crypto_seed_rng(1)) {
00518     fprintf(stderr, "Couldn't seed RNG.\n");
00519     goto done;
00520   }
00521   /* Make sure that files are made private. */
00522   umask(0077);
00523 
00524   if (parse_commandline(argc, argv))
00525     goto done;
00526   if (load_identity_key())
00527     goto done;
00528   if (reuse_signing_key) {
00529     if (load_signing_key())
00530       goto done;
00531   } else {
00532     if (generate_signing_key())
00533       goto done;
00534   }
00535   if (generate_certificate())
00536     goto done;
00537 
00538   r = 0;
00539  done:
00540   clear_passphrase();
00541   if (identity_key)
00542     EVP_PKEY_free(identity_key);
00543   if (signing_key)
00544     EVP_PKEY_free(signing_key);
00545   tor_free(address);
00546 
00547   crypto_global_cleanup();
00548   return r;
00549 }
00550