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 +