Passed
Pull Request — master (#2)
by Tim
02:03
created

SignedElementTrait::getValidatingCertificates()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 5
nop 0
dl 0
loc 19
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\XMLSecurity\XML;
6
7
use Exception;
8
use SimpleSAML\Assert\Assert;
9
use SimpleSAML\XMLSecurity\XML\ds\Signature;
10
use SimpleSAML\XMLSecurity\XMLSecurityKey;
11
12
/**
13
 * Helper trait for processing signed elements.
14
 *
15
 * @package simplesamlphp/xml-security
16
 */
17
trait SignedElementTrait
18
{
19
    /**
20
     * The signature of this element.
21
     *
22
     * @var \SimpleSAML\XMLSecurity\XML\ds\Signature $signature
23
     */
24
    protected Signature $signature;
25
26
27
    /**
28
     * Get the signature element of this object.
29
     *
30
     * @return \SimpleSAML\XMLSecurity\XML\ds\Signature
31
     */
32
    public function getSignature(): ?Signature
33
    {
34
        return $this->signature;
35
    }
36
37
38
    /**
39
     * Initialize a signed element from XML.
40
     *
41
     * @param \SimpleSAML\XMLSecurity\XML\ds\Signature $signature The ds:Signature object
42
     */
43
    protected function setSignature(Signature $signature): void
44
    {
45
        $this->signature = $signature;
46
    }
47
48
49
    /**
50
     * Validate this element against a public key.
51
     *
52
     * true is returned on success, false is returned if we don't have any
53
     * signature we can validate. An exception is thrown if the signature
54
     * validation fails.
55
     *
56
     * @param  \SimpleSAML\XMLSecurity\XMLSecurityKey $key The key we should check against.
57
     * @return bool True on success, false when we don't have a signature.
58
     * @throws \Exception
59
     */
60
    public function validate(XMLSecurityKey $key): bool
61
    {
62
        if ($this->signature === null) {
63
            return false;
64
        }
65
66
        $signer = $this->signature->getSigner();
67
        Assert::eq(
68
            $key->getAlgorithm(),
69
            $this->signature->getAlgorithm(),
70
            'Algorithm provided in key does not match algorithm used in signature.'
71
        );
72
73
        // check the signature
74
        if ($signer->verify($key) === 1) {
75
            return true;
76
        }
77
78
        throw new Exception("Unable to validate Signature");
79
    }
80
81
82
    /**
83
     * Retrieve certificates that sign this element.
84
     *
85
     * @return array Array with certificates.
86
     * @throws \Exception if an error occurs while trying to extract the public key from a certificate.
87
     */
88
    public function getValidatingCertificates(): array
89
    {
90
        $ret = [];
91
        foreach ($this->signature->getCertificates() as $cert) {
92
            // extract the public key from the certificate for validation.
93
            $key = new XMLSecurityKey($this->signature->getAlgorithm(), ['type' => 'public']);
94
            $key->loadKey($cert);
95
96
            try {
97
                // check the signature.
98
                if ($this->validate($key)) {
99
                    $ret[] = $cert;
100
                }
101
            } catch (Exception $e) {
102
                // this certificate does not sign this element.
103
            }
104
        }
105
106
        return $ret;
107
    }
108
}
109