8
8
use Icinga \Application \Logger ;
9
9
use Icinga \File \Storage \TemporaryLocalFileStorage ;
10
10
use Icinga \Module \X509 \Model \X509Certificate ;
11
- use Icinga \Module \X509 \Model \X509CertificateChain ;
12
11
use Icinga \Module \X509 \Model \X509CertificateSubjectAltName ;
13
12
use Icinga \Module \X509 \Model \X509Dn ;
14
13
use Icinga \Module \X509 \Model \X509Target ;
18
17
use ipl \Stdlib \Filter ;
19
18
use ipl \Stdlib \Str ;
20
19
20
+ use function ipl \Stdlib \yield_groups ;
21
+
21
22
class CertificateUtils
22
23
{
23
24
/**
@@ -453,52 +454,39 @@ public static function verifyCertificates(Connection $db)
453
454
$ files ->create ($ caFile , implode ("\n" , $ contents ));
454
455
455
456
$ count = 0 ;
457
+ $ certs = X509Certificate::on ($ db )
458
+ ->with (['chain ' ])
459
+ ->utilize ('chain.target ' )
460
+ ->columns (['chain.id ' , 'certificate ' ])
461
+ ->filter (Filter::equal ('chain.valid ' , false ))
462
+ ->orderBy ('chain.id ' )
463
+ ->orderBy (new Expression ('certificate_link.order ' ), SORT_DESC );
456
464
457
465
$ db ->beginTransaction ();
458
466
459
467
try {
460
- $ chains = X509CertificateChain::on ($ db )->utilize ('target ' );
461
- $ chains
462
- ->columns (['id ' ])
463
- ->filter (Filter::equal ('valid ' , false ));
464
-
465
- foreach ($ chains as $ chain ) {
466
- ++$ count ;
467
-
468
- $ certs = X509Certificate::on ($ db )->utilize ('chain ' );
469
- $ certs
470
- ->columns (['certificate ' ])
471
- ->filter (Filter::equal ('chain.id ' , $ chain ->id ))
472
- ->getSelectBase ()
473
- ->orderBy ('certificate_link.order ' , 'DESC ' );
474
-
475
- $ collection = [];
476
-
477
- foreach ($ certs as $ cert ) {
478
- $ collection [] = $ cert ->certificate ;
479
- }
480
-
468
+ $ caFile = escapeshellarg ($ files ->resolvePath ($ caFile ));
469
+ $ verifyCertsFunc = function (int $ chainId , array $ collection ) use ($ db , $ caFile ) {
470
+ $ certFiles = new TemporaryLocalFileStorage ();
481
471
$ certFile = uniqid ('cert ' );
482
-
483
- $ files ->create ($ certFile , array_pop ($ collection ));
472
+ $ certFiles ->create ($ certFile , array_pop ($ collection ));
484
473
485
474
$ untrusted = '' ;
486
-
487
475
if (! empty ($ collection )) {
488
476
$ intermediateFile = uniqid ('intermediate ' );
489
- $ files ->create ($ intermediateFile , implode ("\n" , $ collection ));
477
+ $ certFiles ->create ($ intermediateFile , implode ("\n" , $ collection ));
490
478
491
479
$ untrusted = sprintf (
492
480
' -untrusted %s ' ,
493
- escapeshellarg ($ files ->resolvePath ($ intermediateFile ))
481
+ escapeshellarg ($ certFiles ->resolvePath ($ intermediateFile ))
494
482
);
495
483
}
496
484
497
485
$ command = sprintf (
498
486
'openssl verify -CAfile %s%s %s 2>&1 ' ,
499
- escapeshellarg ( $ files -> resolvePath ( $ caFile)) ,
487
+ $ caFile ,
500
488
$ untrusted ,
501
- escapeshellarg ($ files ->resolvePath ($ certFile ))
489
+ escapeshellarg ($ certFiles ->resolvePath ($ certFile ))
502
490
);
503
491
504
492
$ output = null ;
@@ -513,18 +501,24 @@ public static function verifyCertificates(Connection $db)
513
501
514
502
preg_match ('/^error \d+ at \d+ depth lookup:(.+)$/m ' , $ output , $ match );
515
503
516
- if (!empty ($ match )) {
504
+ if (! empty ($ match )) {
517
505
$ set = ['invalid_reason ' => trim ($ match [1 ])];
518
506
} else {
519
507
$ set = ['valid ' => 'y ' , 'invalid_reason ' => null ];
520
508
}
521
509
522
510
// TODO: https://github.com/Icinga/ipl-orm/pull/78
523
- $ db ->update (
524
- 'x509_certificate_chain ' ,
525
- $ set ,
526
- ['id = ? ' => $ chain ->id ]
527
- );
511
+ $ db ->update ('x509_certificate_chain ' , $ set , ['id = ? ' => $ chainId ]);
512
+ };
513
+
514
+ $ groupBy = function (X509Certificate $ cert ): array {
515
+ // Group all the certificates by their chain id.
516
+ return [$ cert ->chain ->id , $ cert ->certificate ];
517
+ };
518
+
519
+ foreach (yield_groups ($ certs , $ groupBy ) as $ chainId => $ collection ) {
520
+ ++$ count ;
521
+ $ verifyCertsFunc ($ chainId , $ collection );
528
522
}
529
523
530
524
$ db ->commitTransaction ();
0 commit comments