]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/gadgets.cc
Merged from trunk (r12137, v3.2.0.17+)
[thirdparty/squid.git] / src / ssl / gadgets.cc
1 /*
2 * $Id$
3 */
4
5 #include "squid.h"
6 #include "ssl/gadgets.h"
7 #if HAVE_OPENSSL_X509V3_H
8 #include <openssl/x509v3.h>
9 #endif
10
11 EVP_PKEY * Ssl::createSslPrivateKey()
12 {
13 Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
14
15 if (!pkey)
16 return NULL;
17
18 Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
19
20 if (!rsa)
21 return NULL;
22
23 if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
24 return NULL;
25
26 rsa.release();
27 return pkey.release();
28 }
29
30 /**
31 \ingroup ServerProtocolSSLInternal
32 * Set serial random serial number or set random serial number.
33 */
34 static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
35 {
36 if (!ai)
37 return false;
38 Ssl::BIGNUM_Pointer bn(BN_new());
39 if (serial) {
40 bn.reset(BN_dup(serial));
41 } else {
42 if (!bn)
43 return false;
44
45 if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
46 return false;
47 }
48
49 if (ai && !BN_to_ASN1_INTEGER(bn.get(), ai))
50 return false;
51 return true;
52 }
53
54 bool Ssl::writeCertAndPrivateKeyToMemory(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, std::string & bufferToWrite)
55 {
56 bufferToWrite.clear();
57 if (!pkey || !cert)
58 return false;
59 BIO_Pointer bio(BIO_new(BIO_s_mem()));
60 if (!bio)
61 return false;
62
63 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
64 return false;
65
66 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
67 return false;
68
69 char *ptr = NULL;
70 long len = BIO_get_mem_data(bio.get(), &ptr);
71 if (!ptr)
72 return false;
73
74 bufferToWrite = std::string(ptr, len);
75 return true;
76 }
77
78 bool Ssl::appendCertToMemory(Ssl::X509_Pointer const & cert, std::string & bufferToWrite)
79 {
80 if (!cert)
81 return false;
82
83 BIO_Pointer bio(BIO_new(BIO_s_mem()));
84 if (!bio)
85 return false;
86
87 if (!PEM_write_bio_X509 (bio.get(), cert.get()))
88 return false;
89
90 char *ptr = NULL;
91 long len = BIO_get_mem_data(bio.get(), &ptr);
92 if (!ptr)
93 return false;
94
95 if (!bufferToWrite.empty())
96 bufferToWrite.append(" "); // add a space...
97
98 bufferToWrite.append(ptr, len);
99 return true;
100 }
101
102 bool Ssl::writeCertAndPrivateKeyToFile(Ssl::X509_Pointer const & cert, Ssl::EVP_PKEY_Pointer const & pkey, char const * filename)
103 {
104 if (!pkey || !cert)
105 return false;
106
107 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
108 if (!bio)
109 return false;
110 if (!BIO_write_filename(bio.get(), const_cast<char *>(filename)))
111 return false;
112
113 if (!PEM_write_bio_X509(bio.get(), cert.get()))
114 return false;
115
116 if (!PEM_write_bio_PrivateKey(bio.get(), pkey.get(), NULL, NULL, 0, NULL, NULL))
117 return false;
118
119 return true;
120 }
121
122 bool Ssl::readCertAndPrivateKeyFromMemory(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * bufferToRead)
123 {
124 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
125 BIO_puts(bio.get(), bufferToRead);
126
127 X509 * certPtr = NULL;
128 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
129 if (!cert)
130 return false;
131
132 EVP_PKEY * pkeyPtr = NULL;
133 pkey.reset(PEM_read_bio_PrivateKey(bio.get(), &pkeyPtr, 0, 0));
134 if (!pkey)
135 return false;
136
137 return true;
138 }
139
140 bool Ssl::readCertFromMemory(X509_Pointer & cert, char const * bufferToRead)
141 {
142 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
143 BIO_puts(bio.get(), bufferToRead);
144
145 X509 * certPtr = NULL;
146 cert.reset(PEM_read_bio_X509(bio.get(), &certPtr, 0, 0));
147 if (!cert)
148 return false;
149
150 return true;
151 }
152
153 // According to RFC 5280 (Section A.1), the common name length in a certificate
154 // can be at most 64 characters
155 static const size_t MaxCnLen = 64;
156
157 // Replace certs common name with the given
158 static bool replaceCommonName(Ssl::X509_Pointer & cert, std::string const &cn)
159 {
160 std::string fixedCn;
161 if (cn.length() > MaxCnLen) {
162 // In the case the length od CN is more than the maximum supported size
163 // try to use the first upper level domain.
164 size_t pos = 0;
165 do {
166 pos = cn.find('.', pos + 1);
167 } while(pos != std::string::npos && (cn.length() - pos + 2) > MaxCnLen);
168
169 // If no short domain found or this domain is a toplevel domain
170 // we failed to find a good cn name.
171 if (pos == std::string::npos || cn.find('.', pos + 1) == std::string::npos)
172 return false;
173
174 fixedCn.append(1,'*');
175 fixedCn.append(cn.c_str() + pos);
176 }
177
178 X509_NAME *name = X509_get_subject_name(cert.get());
179 if (!name)
180 return false;
181 // Remove the CN part:
182 int loc = X509_NAME_get_index_by_NID(name, NID_commonName, -1);
183 if (loc >=0) {
184 X509_NAME_ENTRY *tmp = X509_NAME_get_entry(name, loc);
185 X509_NAME_delete_entry(name, loc);
186 X509_NAME_ENTRY_free(tmp);
187 }
188
189 // Add a new CN
190 return X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
191 (unsigned char *)(fixedCn.empty() ? cn.c_str() : fixedCn.c_str()), -1, -1, 0);
192 }
193
194 const char *Ssl::CertSignAlgorithmStr[] = {
195 "signTrusted",
196 "signUntrusted",
197 "signSelf",
198 NULL
199 };
200
201 const char *Ssl::CertAdaptAlgorithmStr[] = {
202 "setValidAfter",
203 "setValidBefore",
204 "setCommonName",
205 NULL
206 };
207
208 Ssl::CertificateProperties::CertificateProperties():
209 setValidAfter(false),
210 setValidBefore(false),
211 setCommonName(false),
212 signAlgorithm(Ssl::algSignEnd)
213 {}
214
215 std::string & Ssl::CertificateProperties::dbKey() const
216 {
217 static std::string certKey;
218 certKey.clear();
219 certKey.reserve(4096);
220 if (mimicCert.get()) {
221 char buf[1024];
222 certKey.append(X509_NAME_oneline(X509_get_subject_name(mimicCert.get()), buf, sizeof(buf)));
223 }
224
225 if (certKey.empty()) {
226 certKey.append("/CN=", 4);
227 certKey.append(commonName);
228 }
229
230 if (setValidAfter)
231 certKey.append("+SetValidAfter=on", 17);
232
233 if (setValidBefore)
234 certKey.append("+SetValidBefore=on", 18);
235
236 if (setCommonName) {
237 certKey.append("+SetCommonName=", 15);
238 certKey.append(commonName);
239 }
240
241 if (signAlgorithm != Ssl::algSignEnd) {
242 certKey.append("+Sign=", 6);
243 certKey.append(certSignAlgorithm(signAlgorithm));
244 }
245
246 return certKey;
247 }
248
249 static bool buildCertificate(Ssl::X509_Pointer & cert, Ssl::CertificateProperties const &properties)
250 {
251 // not an Ssl::X509_NAME_Pointer because X509_REQ_get_subject_name()
252 // returns a pointer to the existing subject name. Nothing to clean here.
253 if (properties.mimicCert.get()) {
254 // Leave subject empty if we cannot extract it from true cert.
255 if (X509_NAME *name = X509_get_subject_name(properties.mimicCert.get())) {
256 // X509_set_subject_name will call X509_dup for name
257 X509_set_subject_name(cert.get(), name);
258 }
259 }
260
261 if (properties.setCommonName || !properties.mimicCert.get()) {
262 // In this case the CN of the certificate given by the user
263 // Ignore errors: it is better to make a certificate with no CN
264 // than to quit ssl_crtd because we cannot make a certificate.
265 // Most errors are caused by user input such as huge domain names.
266 (void)replaceCommonName(cert, properties.commonName);
267 }
268
269 // We should get caCert notBefore and notAfter fields and do not allow
270 // notBefore/notAfter values from certToMimic before/after notBefore/notAfter
271 // fields from caCert.
272 // Currently there is not any way in openssl tollkit to compare two ASN1_TIME
273 // objects.
274 ASN1_TIME *aTime = NULL;
275 if (!properties.setValidBefore && properties.mimicCert.get())
276 aTime = X509_get_notBefore(properties.mimicCert.get());
277 if (!aTime && properties.signWithX509.get())
278 aTime = X509_get_notBefore(properties.signWithX509.get());
279
280 if (aTime) {
281 if (!X509_set_notBefore(cert.get(), aTime))
282 return false;
283 }
284 else if (!X509_gmtime_adj(X509_get_notBefore(cert.get()), (-2)*24*60*60))
285 return false;
286
287 aTime = NULL;
288 if (!properties.setValidAfter && properties.mimicCert.get())
289 aTime = X509_get_notAfter(properties.mimicCert.get());
290 if (!aTime && properties.signWithX509.get())
291 aTime = X509_get_notAfter(properties.signWithX509.get());
292 if (aTime) {
293 if (!X509_set_notAfter(cert.get(), aTime))
294 return false;
295 } else if (!X509_gmtime_adj(X509_get_notAfter(cert.get()), 60*60*24*356*3))
296 return false;
297
298 // mimic the alias and possibly subjectAltName
299 if (properties.mimicCert.get()) {
300 unsigned char *alStr;
301 int alLen;
302 alStr = X509_alias_get0(properties.mimicCert.get(), &alLen);
303 if (alStr) {
304 X509_alias_set1(cert.get(), alStr, alLen);
305 }
306
307 // Mimic subjectAltName unless we used a configured CN: browsers reject
308 // certificates with CN unrelated to subjectAltNames.
309 if (!properties.setCommonName) {
310 int pos=X509_get_ext_by_NID (properties.mimicCert.get(), OBJ_sn2nid("subjectAltName"), -1);
311 X509_EXTENSION *ext=X509_get_ext(properties.mimicCert.get(), pos);
312 if (ext) {
313 X509_add_ext(cert.get(), ext, -1);
314 /* According the RFC 5280 using extensions requires version 3
315 certificate.
316 Set version value to 2 for version 3 certificates.
317 */
318 X509_set_version(cert.get(), 2);
319 }
320 }
321 }
322
323 return true;
324 }
325
326 static bool generateFakeSslCertificate(Ssl::X509_Pointer & certToStore, Ssl::EVP_PKEY_Pointer & pkeyToStore, Ssl::CertificateProperties const &properties, Ssl::BIGNUM_Pointer const &serial)
327 {
328 Ssl::EVP_PKEY_Pointer pkey;
329 // Use signing certificates private key as generated certificate private key
330 if (properties.signWithPkey.get())
331 pkey.resetAndLock(properties.signWithPkey.get());
332 else // if not exist generate one
333 pkey.reset(Ssl::createSslPrivateKey());
334
335 if (!pkey)
336 return false;
337
338 Ssl::X509_Pointer cert(X509_new());
339 if (!cert)
340 return false;
341
342 // Set pub key and serial given by the caller
343 if (!X509_set_pubkey(cert.get(), pkey.get()))
344 return false;
345 if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial.get()))
346 return false;
347
348 // Fill the certificate with the required properties
349 if (!buildCertificate(cert, properties))
350 return false;
351
352 int ret = 0;
353 // Set issuer name, from CA or our subject name for self signed cert
354 if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithX509.get())
355 ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(properties.signWithX509.get()));
356 else // Self signed certificate, set issuer to self
357 ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(cert.get()));
358 if (!ret)
359 return false;
360
361 /*Now sign the request */
362 if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithPkey.get())
363 ret = X509_sign(cert.get(), properties.signWithPkey.get(), EVP_sha1());
364 else //else sign with self key (self signed request)
365 ret = X509_sign(cert.get(), pkey.get(), EVP_sha1());
366
367 if (!ret)
368 return false;
369
370 certToStore.reset(cert.release());
371 pkeyToStore.reset(pkey.release());
372 return true;
373 }
374
375 static BIGNUM *createCertSerial(unsigned char *md, unsigned int n)
376 {
377
378 assert(n == 20); //for sha1 n is 20 (for md5 n is 16)
379
380 BIGNUM *serial = NULL;
381 serial = BN_bin2bn(md, n, NULL);
382
383 // if the serial is "0" set it to '1'
384 if (BN_is_zero(serial))
385 BN_one(serial);
386
387 // serial size does not exceed 20 bytes
388 assert(BN_num_bits(serial) <= 160);
389
390 // According the RFC 5280, serial is an 20 bytes ASN.1 INTEGER (a signed big integer)
391 // and the maximum value for X.509 certificate serial number is 2^159-1 and
392 // the minimum 0. If the first bit of the serial is '1' ( eg 2^160-1),
393 // will result to a negative integer.
394 // To handle this, if the produced serial is greater than 2^159-1
395 // truncate the last bit
396 if (BN_is_bit_set(serial, 159))
397 BN_clear_bit(serial, 159);
398
399 return serial;
400 }
401
402 /// Return the SHA1 digest of the DER encoded version of the certificate
403 /// stored in a BIGNUM
404 static BIGNUM *x509Digest(Ssl::X509_Pointer const & cert)
405 {
406 unsigned int n;
407 unsigned char md[EVP_MAX_MD_SIZE];
408
409 if (!X509_digest(cert.get(),EVP_sha1(),md,&n))
410 return NULL;
411
412 return createCertSerial(md, n);
413 }
414
415 static BIGNUM *x509Pubkeydigest(Ssl::X509_Pointer const & cert)
416 {
417 unsigned int n;
418 unsigned char md[EVP_MAX_MD_SIZE];
419
420 if (!X509_pubkey_digest(cert.get(),EVP_sha1(),md,&n))
421 return NULL;
422
423 return createCertSerial(md, n);
424 }
425
426 /// Generate a unique serial number based on a Ssl::CertificateProperties object
427 /// for a new generated certificate
428 static bool createSerial(Ssl::BIGNUM_Pointer &serial, Ssl::CertificateProperties const &properties)
429 {
430 Ssl::EVP_PKEY_Pointer fakePkey;
431 Ssl::X509_Pointer fakeCert;
432
433 serial.reset(x509Pubkeydigest(properties.signWithX509));
434 if (!serial.get()) {
435 serial.reset(BN_new());
436 BN_is_zero(serial.get());
437 }
438
439 if (!generateFakeSslCertificate(fakeCert, fakePkey, properties, serial))
440 return false;
441
442 // The x509Fingerprint return an SHA1 hash.
443 // both SHA1 hash and maximum serial number size are 20 bytes.
444 BIGNUM *r = x509Digest(fakeCert);
445 if (!r)
446 return false;
447
448 serial.reset(r);
449 return true;
450 }
451
452 bool Ssl::generateSslCertificate(Ssl::X509_Pointer & certToStore, Ssl::EVP_PKEY_Pointer & pkeyToStore, Ssl::CertificateProperties const &properties)
453 {
454 Ssl::BIGNUM_Pointer serial;
455
456 if (!createSerial(serial, properties))
457 return false;
458
459 return generateFakeSslCertificate(certToStore, pkeyToStore, properties, serial);
460 }
461
462 /**
463 \ingroup ServerProtocolSSLInternal
464 * Read certificate from file.
465 */
466 static X509 * readSslX509Certificate(char const * certFilename)
467 {
468 if (!certFilename)
469 return NULL;
470 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
471 if (!bio)
472 return NULL;
473 if (!BIO_read_filename(bio.get(), certFilename))
474 return NULL;
475 X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL);
476 return certificate;
477 }
478
479 EVP_PKEY * Ssl::readSslPrivateKey(char const * keyFilename, pem_password_cb *passwd_callback)
480 {
481 if (!keyFilename)
482 return NULL;
483 Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal()));
484 if (!bio)
485 return NULL;
486 if (!BIO_read_filename(bio.get(), keyFilename))
487 return NULL;
488 EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio.get(), NULL, passwd_callback, NULL);
489 return pkey;
490 }
491
492 void Ssl::readCertAndPrivateKeyFromFiles(Ssl::X509_Pointer & cert, Ssl::EVP_PKEY_Pointer & pkey, char const * certFilename, char const * keyFilename)
493 {
494 if (keyFilename == NULL)
495 keyFilename = certFilename;
496 pkey.reset(readSslPrivateKey(keyFilename));
497 cert.reset(readSslX509Certificate(certFilename));
498 if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) {
499 pkey.reset(NULL);
500 cert.reset(NULL);
501 }
502 }
503
504 bool Ssl::sslDateIsInTheFuture(char const * date)
505 {
506 ASN1_UTCTIME tm;
507 tm.flags = 0;
508 tm.type = 23;
509 tm.data = (unsigned char *)date;
510 tm.length = strlen(date);
511
512 return (X509_cmp_current_time(&tm) > 0);
513 }
514
515 /// Print the time represented by a ASN1_TIME struct to a string using GeneralizedTime format
516 static bool asn1timeToGeneralizedTimeStr(ASN1_TIME *aTime, char *buf, int bufLen)
517 {
518 // ASN1_Time holds time to UTCTime or GeneralizedTime form.
519 // UTCTime has the form YYMMDDHHMMSS[Z | [+|-]offset]
520 // GeneralizedTime has the form YYYYMMDDHHMMSS[Z | [+|-] offset]
521
522 // length should have space for data plus 2 extra bytes for the two extra year fields
523 // plus the '\0' char.
524 if ((aTime->length + 3) > bufLen)
525 return false;
526
527 char *str;
528 if (aTime->type == V_ASN1_UTCTIME) {
529 if (aTime->data[0] > '5') { // RFC 2459, section 4.1.2.5.1
530 buf[0] = '1';
531 buf[1] = '9';
532 } else {
533 buf[0] = '2';
534 buf[1] = '0';
535 }
536 str = buf +2;
537 }
538 else // if (aTime->type == V_ASN1_GENERALIZEDTIME)
539 str = buf;
540
541 memcpy(str, aTime->data, aTime->length);
542 str[aTime->length] = '\0';
543 return true;
544 }
545
546 static int asn1time_cmp(ASN1_TIME *asnTime1, ASN1_TIME *asnTime2)
547 {
548 char strTime1[64], strTime2[64];
549 if (!asn1timeToGeneralizedTimeStr(asnTime1, strTime1, sizeof(strTime1)))
550 return -1;
551 if (!asn1timeToGeneralizedTimeStr(asnTime2, strTime2, sizeof(strTime2)))
552 return -1;
553
554 return strcmp(strTime1, strTime2);
555 }
556
557 bool Ssl::certificateMatchesProperties(X509 *cert, CertificateProperties const &properties)
558 {
559 assert(cert);
560
561 // For non self-signed certificates we have to check if the signing certificate changed
562 if (properties.signAlgorithm != Ssl::algSignSelf) {
563 assert(properties.signWithX509.get());
564 if (X509_check_issued(properties.signWithX509.get(), cert) != X509_V_OK)
565 return false;
566 }
567
568 X509 *cert2 = properties.mimicCert.get();
569 // If there is not certificate to mimic stop here
570 if (!cert2)
571 return true;
572
573 if (!properties.setCommonName) {
574 X509_NAME *cert1_name = X509_get_subject_name(cert);
575 X509_NAME *cert2_name = X509_get_subject_name(cert2);
576 if (X509_NAME_cmp(cert1_name, cert2_name) != 0)
577 return false;
578 }
579 else if (properties.commonName != CommonHostName(cert))
580 return false;
581
582 if (!properties.setValidBefore) {
583 ASN1_TIME *aTime = X509_get_notBefore(cert);
584 ASN1_TIME *bTime = X509_get_notBefore(cert2);
585 if (asn1time_cmp(aTime, bTime) != 0)
586 return false;
587 } else if (X509_cmp_current_time(X509_get_notBefore(cert)) >= 0) {
588 // notBefore does not exist (=0) or it is in the future (>0)
589 return false;
590 }
591
592 if (!properties.setValidAfter) {
593 ASN1_TIME *aTime = X509_get_notAfter(cert);
594 ASN1_TIME *bTime = X509_get_notAfter(cert2);
595 if (asn1time_cmp(aTime, bTime) != 0)
596 return false;
597 } else if (X509_cmp_current_time(X509_get_notAfter(cert)) <= 0) {
598 // notAfter does not exist (0) or it is in the past (<0)
599 return false;
600 }
601
602
603 char *alStr1;
604 int alLen;
605 alStr1 = (char *)X509_alias_get0(cert, &alLen);
606 char *alStr2 = (char *)X509_alias_get0(cert2, &alLen);
607 if ((!alStr1 && alStr2) || (alStr1 && !alStr2) ||
608 (alStr1 && alStr2 && strcmp(alStr1, alStr2)) != 0)
609 return false;
610
611 // Compare subjectAltName extension
612 STACK_OF(GENERAL_NAME) * cert1_altnames;
613 cert1_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
614 STACK_OF(GENERAL_NAME) * cert2_altnames;
615 cert2_altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(cert2, NID_subject_alt_name, NULL, NULL);
616 bool match = true;
617 if (cert1_altnames) {
618 int numalts = sk_GENERAL_NAME_num(cert1_altnames);
619 for (int i = 0; match && i < numalts; i++) {
620 const GENERAL_NAME *aName = sk_GENERAL_NAME_value(cert1_altnames, i);
621 match = sk_GENERAL_NAME_find(cert2_altnames, aName);
622 }
623 }
624 else if (cert2_altnames)
625 match = false;
626
627 sk_GENERAL_NAME_pop_free(cert1_altnames, GENERAL_NAME_free);
628 sk_GENERAL_NAME_pop_free(cert2_altnames, GENERAL_NAME_free);
629
630 return match;
631 }
632
633 static const char *getSubjectEntry(X509 *x509, int nid)
634 {
635 static char name[1024] = ""; // stores common name (CN)
636
637 if (!x509)
638 return NULL;
639
640 // TODO: What if the entry is a UTF8String? See X509_NAME_get_index_by_NID(3ssl).
641 const int nameLen = X509_NAME_get_text_by_NID(
642 X509_get_subject_name(x509),
643 nid, name, sizeof(name));
644
645 if (nameLen > 0)
646 return name;
647
648 return NULL;
649 }
650
651 const char *Ssl::CommonHostName(X509 *x509)
652 {
653 return getSubjectEntry(x509, NID_commonName);
654 }
655
656 const char *Ssl::getOrganization(X509 *x509)
657 {
658 return getSubjectEntry(x509, NID_organizationName);
659 }
660