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