]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/gadgets.cc
Certificate mimicking
[thirdparty/squid.git] / src / ssl / gadgets.cc
1 /*
2 * $Id$
3 */
4
5 #include "config.h"
6 #include "ssl/gadgets.h"
7 #if HAVE_OPENSSL_X509V3_H
8 #include <openssl/x509v3.h>
9 #endif
10
11 /**
12 \ingroup ServerProtocolSSLInternal
13 * Add CN to subject in request.
14 */
15 static bool addCnToRequest(Ssl::X509_REQ_Pointer & request, char const * cn)
16 {
17 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
18 // returns a pointer to the existing subject name. Nothing to clean here.
19 X509_NAME *name = X509_REQ_get_subject_name(request.get());
20 if (!name)
21 return false;
22
23 // The second argument of the X509_NAME_add_entry_by_txt declared as
24 // "char *" on some OS. Use cn_name to avoid compile warnings.
25 static char cn_name[3] = "CN";
26 if (!X509_NAME_add_entry_by_txt(name, cn_name, MBSTRING_ASC, (unsigned char *)cn, -1, -1, 0))
27 return false;
28
29 return true;
30 }
31
32 /**
33 \ingroup ServerProtocolSSLInternal
34 * Make request on sign using private key and hostname.
35 */
36 static bool makeRequest(Ssl::X509_REQ_Pointer & request, Ssl::EVP_PKEY_Pointer const & pkey, char const * host)
37 {
38 if (!X509_REQ_set_version(request.get(), 0L))
39 return false;
40
41 if (!addCnToRequest(request, host))
42 return false;
43
44 if (!X509_REQ_set_pubkey(request.get(), pkey.get()))
45 return false;
46 return true;
47 }
48
49 EVP_PKEY * Ssl::createSslPrivateKey()
50 {
51 Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
52
53 if (!pkey)
54 return NULL;
55
56 Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
57
58 if (!rsa)
59 return NULL;
60
61 if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
62 return NULL;
63
64 rsa.release();
65 return pkey.release();
66 }
67
68 X509_REQ * Ssl::createNewX509Request(Ssl::EVP_PKEY_Pointer const & pkey, const char * hostname)
69 {
70 Ssl::X509_REQ_Pointer request(X509_REQ_new());
71
72 if (!request)
73 return NULL;
74
75 if (!makeRequest(request, pkey, hostname))
76 return NULL;
77 return request.release();
78 }
79
80 /**
81 \ingroup ServerProtocolSSLInternal
82 * Set serial random serial number or set random serial number.
83 */
84 static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
85 {
86 if (!ai)
87 return false;
88 Ssl::BIGNUM_Pointer bn(BN_new());
89 if (serial) {
90 bn.reset(BN_dup(serial));
91 } else {
92 if (!bn)
93 return false;
94
95 if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
96 return false;
97 }
98
99 if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
100 return false;
101 return true;
102 }
103
104 X509 * Ssl::signRequest(Ssl::X509_REQ_Pointer const & request, Ssl::X509_Pointer const & x509, Ssl::EVP_PKEY_Pointer const & pkey, ASN1_TIME * timeNotAfter, BIGNUM const * serial)
105 {
106 Ssl::X509_Pointer cert(X509_new());
107 if (!cert)
108 return NULL;
109
110 if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial))
111 return NULL;
112
113 if (!X509_set_issuer_name(cert.get(), x509.get() ? X509_get_subject_name(x509.get()) : X509_REQ_get_subject_name(request.get())))
114 return NULL;
115
116 if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
117 return NULL;
118
119 if (timeNotAfter) {
120 if (!X509_set_notAfter(cert.get(), timeNotAfter))
121 return NULL;
122 } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
123 return NULL;
124
125 if (!X509_set_subject_name(cert.get(), X509_REQ_get_subject_name(request.get())))
126 return NULL;
127
128 Ssl::EVP_PKEY_Pointer tmppkey(X509_REQ_get_pubkey(request.get()));
129
130 if (!tmppkey || !X509_set_pubkey(cert.get(), tmppkey.get()))
131 return NULL;
132
133 if (!X509_sign(cert.get(), pkey.get(), EVP_sha1()))
134 return NULL;
135
136 return cert.release();
137 }
138
139 bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite)
140 {
141 bufferToWrite.clear();
142 if (!pkey || !cert)
143 return false;
144 BIO_Pointer bio(BIO_new(BIO_s_mem()));
145 if (!bio)
146 return false;
147
148 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
149 return false;
150
151 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
152 return false;
153
154 char *ptr = NULL;
155 long len = BIO_get_mem_data(bio.get(), &ptr);
156 if (!ptr)
157 return false;
158
159 bufferToWrite = std::string(ptr, len);
160 return true;
161 }
162
163 bool Ssl::appendCertToMemory(Ssl::X509_Pointer const & cert, std::string & bufferToWrite)
164 {
165 if (!cert)
166 return false;
167
168 BIO_Pointer bio(BIO_new(BIO_s_mem()));
169 if (!bio)
170 return false;
171
172 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
173 return false;
174
175 char *ptr = NULL;
176 long len = BIO_get_mem_data(bio.get(), &ptr);
177 if (!ptr)
178 return false;
179
180 if (!bufferToWrite.empty())
181 bufferToWrite.append(" "); // add a space...
182
183 bufferToWrite.append(ptr, len);
184 return true;
185 }
186
187 bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
188 {
189 if (!pkey || !cert)
190 return false;
191
192 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
193 if (!bio)
194 return false;
195 if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
196 return false;
197
198 if (!PEM_write_bio_X509(bio.get(), cert.get()))
199 return false;
200
201 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
202 return false;
203
204 return true;
205 }
206
207 bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
208 {
209 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
210 BIO_puts(bio.get(), bufferToRead);
211
212 X509 * certPtr = NULL;
213 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
214 if (!cert)
215 return false;
216
217 EVP_PKEY * pkeyPtr = NULL;
218 pkey.reset(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, 0, 0));
219 if (!pkey)
220 return false;
221
222 return true;
223 }
224
225 bool Ssl::readCertFromMemory(X509_Pointer & cert, char const * bufferToRead)
226 {
227 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
228 BIO_puts(bio.get(), bufferToRead);
229
230 X509 * certPtr = NULL;
231 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
232 if (!cert)
233 return false;
234
235 return true;
236 }
237
238 bool Ssl::generateSslCertificateAndPrivateKey(char const *host, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, BIGNUM const * serial)
239 {
240 pkey.reset(createSslPrivateKey());
241 if (!pkey)
242 return false;
243
244 Ssl::X509_REQ_Pointer request(createNewX509Request(pkey, host));
245 if (!request)
246 return false;
247
248 if (signedX509.get() && signedPkey.get())
249 cert.reset(signRequest(request, signedX509, signedPkey, X509_get_notAfter(signedX509.get()), serial));
250 else
251 cert.reset(signRequest(request, signedX509, pkey, NULL, serial));
252
253 if (!cert)
254 return false;
255
256 return true;
257 }
258
259 static bool mimicCertificate(Ssl::X509_Pointer & cert, Ssl::X509_Pointer const & caCert, Ssl::X509_Pointer const &certToMimic)
260 {
261 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
262 // returns a pointer to the existing subject name. Nothing to clean here.
263 X509_NAME *name = X509_get_subject_name(certToMimic.get());
264 if (!name)
265 return false;
266 // X509_set_subject_name will call X509_dup for name
267 X509_set_subject_name(cert.get(), name);
268
269
270 // We should get caCert notBefore and notAfter fields and do not allow
271 // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
272 // fields from caCert.
273 // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
274 // objects.
275 ASN1_TIME *aTime;
276 if ((aTime = X509_get_notBefore(certToMimic.get())) || (aTime = X509_get_notBefore(caCert.get())) ) {
277 if (!X509_set_notBefore(cert.get(), aTime))
278 return false;
279 }
280 else if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
281 return false;
282
283 if ((aTime = X509_get_notAfter(certToMimic.get())) || (aTime = X509_get_notAfter(caCert.get())) ) {
284 if (!X509_set_notAfter(cert.get(), aTime))
285 return NULL;
286 } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
287 return NULL;
288
289
290 unsigned char *alStr;
291 int alLen;
292 alStr = X509_alias_get0(certToMimic.get(), &alLen);
293 if (alStr) {
294 X509_alias_set1(cert.get(), alStr, alLen);
295 }
296
297 // Add subjectAltName extension used to support multiple hostnames with one certificate
298 int pos=X509_get_ext_by_NID (certToMimic.get(), OBJ_sn2nid("subjectAltName"), -1);
299 X509_EXTENSION *ext=X509_get_ext(certToMimic.get(), pos);
300 if (ext)
301 X509_add_ext(cert.get(), ext, -1);
302
303 return true;
304 }
305
306 bool Ssl::generateSslCertificate(Ssl::X509_Pointer const &certToMimic, Ssl::X509_Pointer const & signedX509, Ssl::EVP_PKEY_Pointer const & signedPkey, Ssl::X509_Pointer & certToStore, Ssl::EVP_PKEY_Pointer & pkey, BIGNUM const * serial)
307 {
308 if (!certToMimic.get())
309 return false;
310
311 pkey.reset(createSslPrivateKey());
312 if (!pkey)
313 return false;
314
315 Ssl::X509_Pointer cert(X509_new());
316 if (!cert)
317 return false;
318
319 // Set pub key and serial given by the caller
320 if (!X509_set_pubkey(cert.get(), pkey.get()))
321 return false;
322 if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial))
323 return false;
324
325 // inherit properties from certToMimic
326 if (!mimicCertificate(cert, signedX509, certToMimic))
327 return false;
328
329 // Set issuer name, from CA or our subject name for self signed cert
330 if (!X509_set_issuer_name(cert.get(), signedX509.get() ? X509_get_subject_name(signedX509.get()) : X509_get_subject_name(cert.get())))
331 return false;
332
333 /*Now sign the request */
334 int ret = 0;
335 if (signedPkey.get())
336 ret = X509_sign(cert.get(), signedPkey.get(), EVP_sha1());
337 else //else sign with self key (self signed request)
338 ret = X509_sign(cert.get(), pkey.get(), EVP_sha1());
339
340 if (!ret)
341 return false;
342
343 certToStore.reset(cert.release());
344 return true;
345 }
346
347 /**
348 \ingroup ServerProtocolSSLInternal
349 * Read certificate from file.
350 */
351 static X509 * readSslX509Certificate(char const * certFilename)
352 {
353 if (!certFilename)
354 return NULL;
355 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
356 if (!bio)
357 return NULL;
358 if (!BIO_read_filename(bio.get(), certFilename))
359 return NULL;
360 X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
361 return certificate;
362 }
363
364 EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename)
365 {
366 if (!keyFilename)
367 return NULL;
368 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
369 if (!bio)
370 return NULL;
371 if (!BIO_read_filename(bio.get(), keyFilename))
372 return NULL;
373 EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL);
374 return pkey;
375 }
376
377 void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
378 {
379 if (keyFilename == NULL)
380 keyFilename = certFilename;
381 pkey.reset(readSslPrivateKey(keyFilename));
382 cert.reset(readSslX509Certificate(certFilename));
383 if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
384 pkey.reset(NULL);
385 cert.reset(NULL);
386 }
387 }
388
389 bool Ssl::sslDateIsInTheFuture(char const * date)
390 {
391 ASN1_UTCTIME tm;
392 tm.flags = 0;
393 tm.type = 23;
394 tm.data = (unsigned char *)date;
395 tm.length = strlen(date);
396
397 return (X509_cmp_current_time(&tm) > 0);
398 }