1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #ifdef MUMBLE
7 	#include "mumble_pch.hpp"
8 #else
9 	#include "murmur_pch.h"
10 #endif
11 
12 #include "SelfSignedCertificate.h"
13 
14 #define SSL_STRING(x) QString::fromLatin1(x).toUtf8().data()
15 
add_ext(X509 * crt,int nid,char * value)16 static int add_ext(X509 * crt, int nid, char *value) {
17 	X509V3_CTX ctx;
18 	X509V3_set_ctx_nodb(&ctx);
19 	X509V3_set_ctx(&ctx, crt, crt, NULL, NULL, 0);
20 
21 	X509_EXTENSION *ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
22 	if (ex == NULL) {
23 		return 0;
24 	}
25 
26 	if (X509_add_ext(crt, ex, -1) == 0) {
27 		X509_EXTENSION_free(ex);
28 		return 0;
29 	}
30 
31 	X509_EXTENSION_free(ex);
32 	return 1;
33 }
34 
generate(CertificateType certificateType,QString clientCertName,QString clientCertEmail,QSslCertificate & qscCert,QSslKey & qskKey)35 bool SelfSignedCertificate::generate(CertificateType certificateType, QString clientCertName, QString clientCertEmail, QSslCertificate &qscCert, QSslKey &qskKey) {
36 	bool ok = true;
37 	X509 *x509 = NULL;
38 	EVP_PKEY *pkey = NULL;
39 	RSA *rsa = NULL;
40 	BIGNUM *e = NULL;
41 	X509_NAME *name = NULL;
42 	ASN1_INTEGER *serialNumber = NULL;
43 	ASN1_TIME *notBefore = NULL;
44 	ASN1_TIME *notAfter = NULL;
45 	QString commonName;
46 	bool isServerCert = certificateType == CertificateTypeServerCertificate;
47 
48 	if (CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON) == -1) {
49 		ok = false;
50 		goto out;
51 	}
52 
53 	x509 = X509_new();
54 	if (x509 == NULL) {
55 		ok = false;
56 		goto out;
57 	}
58 
59 	pkey = EVP_PKEY_new();
60 	if (pkey == NULL) {
61 		ok = false;
62 		goto out;
63 	}
64 
65 	rsa = RSA_new();
66 	if (rsa == NULL) {
67 		ok = false;
68 		goto out;
69 	}
70 
71 	e = BN_new();
72 	if (e == NULL) {
73 		ok = false;
74 		goto out;
75 	}
76 	if (BN_set_word(e, 65537) == 0) {
77 		ok = false;
78 		goto out;
79 	}
80 
81 	if (RSA_generate_key_ex(rsa, 2048, e, NULL) == 0) {
82 		ok = false;
83 		goto out;
84 	}
85 
86 	if (EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
87 		ok = false;
88 		goto out;
89 	}
90 
91 	if (X509_set_version(x509, 2) == 0) {
92 		ok = false;
93 		goto out;
94 	}
95 
96 	serialNumber = X509_get_serialNumber(x509);
97 	if (serialNumber == NULL) {
98 		ok = false;
99 		goto out;
100 	}
101 	if (ASN1_INTEGER_set(serialNumber, 1) == 0) {
102 		ok = false;
103 		goto out;
104 	}
105 
106 	notBefore = X509_get_notBefore(x509);
107 	if (notBefore == NULL) {
108 		ok = false;
109 		goto out;
110 	}
111 	if (X509_gmtime_adj(notBefore, 0) == NULL) {
112 		ok = false;
113 		goto out;
114 	}
115 
116 	notAfter = X509_get_notAfter(x509);
117 	if (notAfter == NULL) {
118 		ok = false;
119 		goto out;
120 	}
121 	if (X509_gmtime_adj(notAfter, 60*60*24*365*20) == NULL) {
122 		ok = false;
123 		goto out;
124 	}
125 
126 	if (X509_set_pubkey(x509, pkey) == 0) {
127 		ok = false;
128 		goto out;
129 	}
130 
131 	name = X509_get_subject_name(x509);
132 	if (name == NULL) {
133 		ok = false;
134 		goto out;
135 	}
136 
137 	if (isServerCert) {
138 		commonName = QLatin1String("Murmur Autogenerated Certificate v2");
139 	} else {
140 		if (!clientCertName.isEmpty()) {
141 			commonName = clientCertName;
142 		} else {
143 			commonName = QLatin1String("Mumble User");
144 		}
145 	}
146 
147 	if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, reinterpret_cast<unsigned char *>(commonName.toUtf8().data()), -1, -1, 0) == 0) {
148 		ok = false;
149 		goto out;
150 	}
151 
152 	if (X509_set_issuer_name(x509, name) == 0) {
153 		ok = false;
154 		goto out;
155 	}
156 
157 	if (add_ext(x509, NID_basic_constraints, SSL_STRING("critical,CA:FALSE")) == 0) {
158 		ok = false;
159 		goto out;
160 	}
161 
162 	if (isServerCert) {
163 		if (add_ext(x509, NID_ext_key_usage, SSL_STRING("serverAuth,clientAuth")) == 0) {
164 			ok = false;
165 			goto out;
166 		}
167 	} else {
168 		if (add_ext(x509, NID_ext_key_usage, SSL_STRING("clientAuth")) == 0) {
169 			ok = false;
170 			goto out;
171 		}
172 	}
173 
174 	if (add_ext(x509, NID_subject_key_identifier, SSL_STRING("hash")) == 0) {
175 		ok = false;
176 		goto out;
177 	}
178 
179 	if (isServerCert) {
180 		if (add_ext(x509, NID_netscape_comment, SSL_STRING("Generated from murmur")) == 0) {
181 			ok = false;
182 			goto out;
183 		}
184 	} else {
185 		if (add_ext(x509, NID_netscape_comment, SSL_STRING("Generated by Mumble")) == 0) {
186 			ok = false;
187 			goto out;
188 		}
189 	}
190 
191 	if (!isServerCert) {
192 		if (!clientCertEmail.trimmed().isEmpty()) {
193 			if (add_ext(x509, NID_subject_alt_name, QString::fromLatin1("email:%1").arg(clientCertEmail).toUtf8().data()) == 0) {
194 				ok = false;
195 				goto out;
196 			}
197 		}
198 	}
199 
200 	if (X509_sign(x509, pkey, EVP_sha1()) == 0) {
201 		ok = false;
202 		goto out;
203 	}
204 
205 	{
206 		QByteArray crt;
207 		int len = i2d_X509(x509, NULL);
208 		if (len <= 0) {
209 			ok = false;
210 			goto out;
211 		}
212 		crt.resize(len);
213 
214 		unsigned char *dptr = reinterpret_cast<unsigned char *>(crt.data());
215 		if (i2d_X509(x509, &dptr) != len) {
216 			ok = false;
217 			goto out;
218 		}
219 
220 		qscCert = QSslCertificate(crt, QSsl::Der);
221 		if (qscCert.isNull()) {
222 			ok = false;
223 			goto out;
224 		}
225 	}
226 
227 	{
228 		QByteArray key;
229 		int len = i2d_PrivateKey(pkey, NULL);
230 		if (len <= 0) {
231 			ok = false;
232 			goto out;
233 		}
234 		key.resize(len);
235 
236 		unsigned char *dptr = reinterpret_cast<unsigned char *>(key.data());
237 		if (i2d_PrivateKey(pkey, &dptr) != len) {
238 			ok = false;
239 			goto out;
240 		}
241 
242 		qskKey = QSslKey(key, QSsl::Rsa, QSsl::Der);
243 		if (qskKey.isNull()) {
244 			ok = false;
245 			goto out;
246 		}
247 	}
248 
249 out:
250 	if (e) {
251 		BN_free(e);
252 	}
253 	// We only need to free the pkey pointer,
254 	// not the RSA pointer. We have assigned
255 	// our RSA key to pkey, and it will be freed
256 	// once we free pkey.
257 	if (pkey) {
258 		EVP_PKEY_free(pkey);
259 	}
260 	if (x509) {
261 		X509_free(x509);
262 	}
263 
264 	if (!ok) {
265 		qscCert = QSslCertificate();
266 		qskKey = QSslKey();
267 	}
268 
269 	return ok;
270 }
271 
generateMumbleCertificate(QString name,QString email,QSslCertificate & qscCert,QSslKey & qskKey)272 bool SelfSignedCertificate::generateMumbleCertificate(QString name, QString email, QSslCertificate &qscCert, QSslKey &qskKey) {
273 	return SelfSignedCertificate::generate(CertificateTypeClientCertificate, name, email, qscCert, qskKey);
274 }
275 
generateMurmurV2Certificate(QSslCertificate & qscCert,QSslKey & qskKey)276 bool SelfSignedCertificate::generateMurmurV2Certificate(QSslCertificate &qscCert, QSslKey &qskKey) {
277 	return SelfSignedCertificate::generate(CertificateTypeServerCertificate, QString(), QString(), qscCert, qskKey);
278 }
279