diff --git a/src/client.c b/src/client.c
index 472e29d..21d33d3 100644
--- a/src/client.c
+++ b/src/client.c
@@ -19,6 +19,7 @@
#include "http.h"
#include "xml.h"
+#include "mkcert.h"
#include "limelight-common/Limelight.h"
@@ -35,6 +36,7 @@
static const char *uniqueFileName = "uniqueid.dat";
static const char *certificateFileName = "client.pem";
+static const char *p12FileName = "client.p12";
static const char *keyFileName = "key.pem";
static char unique_id[17];
@@ -65,7 +67,15 @@ static void client_load_unique_id() {
static void client_load_cert() {
FILE *fd = fopen(certificateFileName, "r");
if (fd == NULL) {
- fprintf(stderr, "Can't open certificate file");
+ printf("Generating certificate\n");
+ struct CertKeyPair cert = generateCertKeyPair();
+ saveCertKeyPair(certificateFileName, p12FileName, keyFileName, cert);
+ freeCertKeyPair(cert);
+ fd = fopen(certificateFileName, "r");
+ }
+
+ if (fd == NULL) {
+ fprintf(stderr, "Can't open certificate file\n");
exit(-1);
}
diff --git a/src/mkcert.c b/src/mkcert.c
new file mode 100644
index 0000000..fc8d327
--- /dev/null
+++ b/src/mkcert.c
@@ -0,0 +1,176 @@
+/*
+ * Moonlight is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Moonlight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Moonlight; if not, see .
+ */
+
+#include "mkcert.h"
+
+#include
+#include
+
+#include
+#include
+#include
+
+#ifndef OPENSSL_NO_ENGINE
+#include
+#endif
+
+static const int NUM_BITS = 2048;
+static const int SERIAL = 0;
+static const int NUM_YEARS = 10;
+
+int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years);
+int add_ext(X509 *cert, int nid, char *value);
+
+struct CertKeyPair generateCertKeyPair() {
+ BIO *bio_err;
+ X509 *x509 = NULL;
+ EVP_PKEY *pkey = NULL;
+ PKCS12 *p12 = NULL;
+
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ SSLeay_add_all_algorithms();
+ ERR_load_crypto_strings();
+
+ mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS);
+
+ p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
+ if (p12 == NULL) {
+ printf("Error generating a valid PKCS12 certificate.\n");
+ }
+
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_cleanup();
+#endif
+ CRYPTO_cleanup_all_ex_data();
+
+ CRYPTO_mem_leaks(bio_err);
+ BIO_free(bio_err);
+
+ return (CertKeyPair){x509, pkey, p12};
+}
+
+void freeCertKeyPair(struct CertKeyPair certKeyPair) {
+ X509_free(certKeyPair.x509);
+ EVP_PKEY_free(certKeyPair.pkey);
+ PKCS12_free(certKeyPair.p12);
+}
+
+void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair) {
+ FILE* certFilePtr = fopen(certFile, "w");
+ FILE* keyPairFilePtr = fopen(keyPairFile, "w");
+ FILE* p12FilePtr = fopen(p12File, "wb");
+
+ //TODO: error check
+ PEM_write_PrivateKey(keyPairFilePtr, certKeyPair.pkey, NULL, NULL, 0, NULL, NULL);
+ PEM_write_X509(certFilePtr, certKeyPair.x509);
+ i2d_PKCS12_fp(p12FilePtr, certKeyPair.p12);
+
+ fclose(p12FilePtr);
+ fclose(certFilePtr);
+ fclose(keyPairFilePtr);
+}
+
+int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
+ X509 *x;
+ EVP_PKEY *pk;
+ RSA *rsa;
+ X509_NAME *name = NULL;
+
+ if (*pkeyp == NULL) {
+ if ((pk=EVP_PKEY_new()) == NULL) {
+ abort();
+ return(0);
+ }
+ } else {
+ pk = *pkeyp;
+ }
+
+ if (*x509p == NULL) {
+ if ((x = X509_new()) == NULL) {
+ goto err;
+ }
+ } else {
+ x = *x509p;
+ }
+
+ rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
+ if (!EVP_PKEY_assign_RSA(pk, rsa)) {
+ abort();
+ goto err;
+ }
+
+ X509_set_version(x, 2);
+ ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
+ X509_gmtime_adj(X509_get_notBefore(x), 0);
+ X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*365*years);
+ X509_set_pubkey(x, pk);
+
+ name = X509_get_subject_name(x);
+
+ /* This function creates and adds the entry, working out the
+ * correct string type and performing checks on its length.
+ */
+ X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char*)"NVIDIA GameStream Client", -1, -1, 0);
+
+ /* Its self signed so set the issuer name to be the same as the
+ * subject.
+ */
+ X509_set_issuer_name(x, name);
+
+ /* Add various extensions: standard extensions */
+ add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
+ add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
+
+ add_ext(x, NID_subject_key_identifier, "hash");
+
+ if (!X509_sign(x, pk, EVP_sha1())) {
+ goto err;
+ }
+
+ *x509p = x;
+ *pkeyp = pk;
+
+ return(1);
+err:
+ return(0);
+}
+
+/* Add extension using V3 code: we can set the config file as NULL
+ * because we wont reference any other sections.
+ */
+
+int add_ext(X509 *cert, int nid, char *value)
+{
+ X509_EXTENSION *ex;
+ X509V3_CTX ctx;
+ /* This sets the 'context' of the extensions. */
+ /* No configuration database */
+ X509V3_set_ctx_nodb(&ctx);
+ /* Issuer and subject certs: both the target since it is self signed,
+ * no request and no CRL
+ */
+ X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
+ ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
+ if (!ex) {
+ return 0;
+ }
+
+ X509_add_ext(cert, ex, -1);
+ X509_EXTENSION_free(ex);
+ return 1;
+}
+
diff --git a/src/mkcert.h b/src/mkcert.h
new file mode 100644
index 0000000..4e14b01
--- /dev/null
+++ b/src/mkcert.h
@@ -0,0 +1,35 @@
+/*
+ * Created by Diego Waxemberg on 10/16/14.
+ * Copyright (c) 2014 Limelight Stream. All rights reserved.
+ *
+ * Moonlight is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Moonlight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Moonlight; if not, see .
+ */
+
+#ifndef Limelight_mkcert_h
+#define Limelight_mkcert_h
+
+#include
+#include
+
+typedef struct CertKeyPair {
+ X509 *x509;
+ EVP_PKEY *pkey;
+ PKCS12 *p12;
+} CertKeyPair;
+
+struct CertKeyPair generateCertKeyPair();
+void freeCertKeyPair(CertKeyPair);
+void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair);
+#endif
+