diff --git a/lib/crypto.c b/lib/crypto.c index 41e8abd..2f9e7c2 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -423,12 +423,12 @@ ed25519_key_t *ed25519_key_generate(const char *keyfile) { BIO *bp; FILE *file; bool new_pk = false; - - + bool use_keyfile = strlen(keyfile); + key = calloc(1, sizeof(ed25519_key_t)); assert(key); - if (keyfile) { + if (use_keyfile) { file = fopen(keyfile, "r"); if (file) { bp = BIO_new_fp(file, BIO_NOCLOSE); @@ -457,15 +457,13 @@ ed25519_key_t *ed25519_key_generate(const char *keyfile) { handle_error(__func__); } EVP_PKEY_CTX_free(pctx); - if (keyfile) { + if (use_keyfile) { file = fopen(keyfile, "w"); if (file) { bp = BIO_new_fp(file, BIO_NOCLOSE); PEM_write_bio_PrivateKey(bp, key->pkey, NULL, NULL, 0, NULL, NULL); BIO_free(bp); fclose(file); - } else { - printf("fopen failed, errno = %d\n", errno); } } } diff --git a/lib/crypto.h b/lib/crypto.h index c0cf221..c6cf434 100644 --- a/lib/crypto.h +++ b/lib/crypto.h @@ -83,7 +83,7 @@ int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *pl typedef struct ed25519_key_s ed25519_key_t; const unsigned char* ed25519_secret_key(const ed25519_key_t *key); -ed25519_key_t *ed25519_key_generate(void); +ed25519_key_t *ed25519_key_generate(const char * keyfile); ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]); void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key); /* diff --git a/lib/pairing.c b/lib/pairing.c index fe38644..9cc978f 100644 --- a/lib/pairing.c +++ b/lib/pairing.c @@ -80,7 +80,7 @@ derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsig } pairing_t * -pairing_init_generate() +pairing_init_generate(const char * keyfile) { pairing_t *pairing; @@ -89,7 +89,7 @@ pairing_init_generate() return NULL; } - pairing->ed = ed25519_key_generate(); + pairing->ed = ed25519_key_generate(keyfile); return pairing; } diff --git a/lib/pairing.h b/lib/pairing.h index 04d2c3e..0648cc3 100644 --- a/lib/pairing.h +++ b/lib/pairing.h @@ -35,7 +35,7 @@ typedef struct pairing_s pairing_t; typedef struct pairing_session_s pairing_session_t; -pairing_t *pairing_init_generate(); +pairing_t *pairing_init_generate(const char * keyfile); void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE]); pairing_session_t *pairing_session_init(pairing_t *pairing); diff --git a/lib/raop.c b/lib/raop.c index ac98577..d656b8a 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -397,7 +397,7 @@ conn_destroy(void *ptr) { } raop_t * -raop_init(int max_clients, raop_callbacks_t *callbacks) { +raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile) { raop_t *raop; pairing_t *pairing; httpd_t *httpd; @@ -428,7 +428,7 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) { raop->logger = logger_init(); /* create a new public key for pairing */ - pairing = pairing_init_generate(); + pairing = pairing_init_generate(keyfile); if (!pairing) { free(raop); return NULL; @@ -610,6 +610,7 @@ int raop_start(raop_t *raop, unsigned short *port) { assert(raop); assert(port); + logger_log(raop->logger, LOGGER_DEBUG, "using Public Key:\n%s", raop->pk_str); return httpd_start(raop->httpd, port); } diff --git a/lib/raop.h b/lib/raop.h index 083b200..e093476 100644 --- a/lib/raop.h +++ b/lib/raop.h @@ -65,7 +65,7 @@ typedef struct raop_callbacks_s raop_callbacks_t; raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol); -RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks); + RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks, const char* keyfile); RAOP_API void raop_set_log_level(raop_t *raop, int level); RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls); RAOP_API int raop_set_plist(raop_t *raop, const char *plist_item, const int value); diff --git a/uxplay.1 b/uxplay.1 index 3171eec..e5de31c 100644 --- a/uxplay.1 +++ b/uxplay.1 @@ -116,6 +116,8 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server: .TP \fB\-m\fR Use random MAC address (use for concurrent UxPlay's) .TP +\fB\-key\fI fn \fR Store private key in file fn (Default: $HOME/.uxplay.pem) +.TP \fB\-vdmp\fR [n] Dump h264 video output to "fn.h264"; fn="videodump", change .IP with "-vdmp [n] filename". If [n] is given, file fn.x.h264 @@ -141,6 +143,7 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server: \fB\-h\fR Displays help information .SH FILES +Private key stored (for persistence) in $HOME/.uxplay.pem (can be changed) .TP Options in one of $UXPLAYRC, or ~/.uxplayrc, or ~/.config/uxplayrc .TP diff --git a/uxplay.cpp b/uxplay.cpp index c64cd7a..6e8f43c 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -129,6 +129,7 @@ static bool restrict_clients; static bool setup_legacy_pairing = false; static bool require_password = false; static unsigned short pin = 0; +static std::string keyfile = ""; /* logging */ @@ -666,6 +667,7 @@ static void print_info (char *name) { printf("-f {H|V|I}Horizontal|Vertical flip, or both=Inversion=rotate 180 deg\n"); printf("-r {R|L} Rotate 90 degrees Right (cw) or Left (ccw)\n"); printf("-m Use random MAC address (use for concurrent UxPlay's)\n"); + printf("-key Store private key in file (default:$HOME/.uxplay.pem)\n"); printf("-vdmp [n] Dump h264 video output to \"fn.h264\"; fn=\"videodump\",change\n"); printf(" with \"-vdmp [n] filename\". If [n] is given, file fn.x.h264\n"); printf(" x=1,2,.. opens whenever a new SPS/PPS NAL arrives, and <=n\n"); @@ -1090,6 +1092,14 @@ static void parse_arguments (int argc, char *argv[]) { } pin = n + 10000; } + } else if (arg == "-key") { + keyfile.erase(); + if (i < argc - 1 && *argv[i+1] != '-') { + keyfile.append(argv[++i]); + } else { + fprintf(stderr, "option \"-key \" requires a path to a file for persistent key storage\n"); + exit(1); + } } else { fprintf(stderr, "unknown option %s, stopping (for help use option \"-h\")\n",argv[i]); exit(1); @@ -1595,7 +1605,7 @@ int start_raop_server (unsigned short display[5], unsigned short tcp[3], unsigne raop_cbs.display_pin = display_pin; /* set max number of connections = 2 to protect against capture by new client */ - raop = raop_init(max_connections, &raop_cbs); + raop = raop_init(max_connections, &raop_cbs, keyfile.c_str()); if (raop == NULL) { LOGE("Error initializing raop!"); return -1; @@ -1812,8 +1822,8 @@ int main (int argc, char *argv[]) { if (videosink == "d3d11videosink" && use_video) { videosink.append(" fullscreen-toggle-mode=alt-enter"); - printf("d3d11videosink is being used with option fullscreen-toggle-mode=alt-enter\n" - "Use Alt-Enter key combination to toggle into/out of full-screen mode\n"); + LOGI("d3d11videosink is being used with option fullscreen-toggle-mode=alt-enter\n" + "Use Alt-Enter key combination to toggle into/out of full-screen mode"); } if (bt709_fix && use_video) { @@ -1821,6 +1831,21 @@ int main (int argc, char *argv[]) { video_parser.append(BT709_FIX); } + if (require_password && keyfile == "") { + const char * homedir = get_homedir(); + if (homedir) { + keyfile.erase(); + keyfile = homedir; + keyfile.append("/.uxplay.pem"); + } else { + LOGE("could not determine $HOME: public key wiil no be saved, and so will not be persistent"); + } + } + + if (keyfile != "") { + LOGI("public key storage (for persistence) is in %s", keyfile.c_str()); + } + if (do_append_hostname) { append_hostname(server_name); }