Passed
Pull Request — master (#2)
by Tim
09:21
created

SignableElementTrait::setSignature()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 4
rs 10
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 SignableElementTrait
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|null
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|null $signature The ds:Signature object
42
     */
43
    protected function setSignature(?Signature $signature): void
44
    {
45
        if ($signature) {
46
            $this->signature = $signature;
47
        }
48
    }
49
50
51
    /**
52
     * Validate this element against a public key.
53
     *
54
     * true is returned on success, false is returned if we don't have any
55
     * signature we can validate. An exception is thrown if the signature
56
     * validation fails.
57
     *
58
     * @param  \SimpleSAML\XMLSecurity\XMLSecurityKey $key The key we should check against.
59
     * @return bool True on success, false when we don't have a signature.
60
     * @throws \Exception
61
     */
62
    public function validate(XMLSecurityKey $key): bool
63
    {
64
        if ($this->signature === null) {
65
            return false;
66
        }
67
68
        $signer = $this->signature->getSigner();
69
        Assert::eq(
70
            $key->getAlgorithm(),
71
            $this->signature->getAlgorithm(),
72
            'Algorithm provided in key does not match algorithm used in signature.'
73
        );
74
75
        // check the signature
76
        if ($signer->verify($key) === 1) {
77
            return true;
78
        }
79
80
        throw new Exception("Unable to validate Signature");
81
    }
82
83
84
    /**
85
     * Retrieve certificates that sign this element.
86
     *
87
     * @return array Array with certificates.
88
     * @throws \Exception if an error occurs while trying to extract the public key from a certificate.
89
     */
90
    public function getValidatingCertificates(): array
91
    {
92
        if ($this->signature === null) {
93
            return [];
94
        }
95
        $ret = [];
96
        foreach ($this->signature->getCertificates() as $cert) {
97
            // extract the public key from the certificate for validation.
98
            $key = new XMLSecurityKey($this->signature->getAlgorithm(), ['type' => 'public']);
99
            $key->loadKey($cert);
100
101
            try {
102
                // check the signature.
103
                if ($this->validate($key)) {
104
                    $ret[] = $cert;
105
                }
106
            } catch (Exception $e) {
107
                // this certificate does not sign this element.
108
            }
109
        }
110
111
        return $ret;
112
    }
113
}
114