Completed
Push — master ( 7210ec...8e6e06 )
by Florent
08:52
created

Loader::decryptCEK()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 14
rs 8.8571
cc 5
eloc 11
nc 5
nop 5
1
<?php
2
3
/*
4
 * The MIT License (MIT)
5
 *
6
 * Copyright (c) 2014-2015 Spomky-Labs
7
 *
8
 * This software may be modified and distributed under the terms
9
 * of the MIT license.  See the LICENSE file for details.
10
 */
11
12
namespace Jose;
13
14
use Base64Url\Base64Url;
15
use Jose\Algorithm\JWAManagerInterface;
16
use Jose\Behaviour\HasCheckerManager;
17
use Jose\Behaviour\HasCompressionManager;
18
use Jose\Behaviour\HasJWAManager;
19
use Jose\Behaviour\HasJWKFinderManager;
20
use Jose\Behaviour\HasKeyChecker;
21
use Jose\Behaviour\HasPayloadConverter;
22
use Jose\Checker\CheckerManagerInterface;
23
use Jose\Compression\CompressionManagerInterface;
24
use Jose\Finder\JWKFinderManagerInterface;
25
use Jose\Object\JWE;
26
use Jose\Object\JWS;
27
use Jose\Payload\PayloadConverterManagerInterface;
28
use Jose\Util\Converter;
29
30
/**
31
 * Class able to load JWS or JWE.
32
 * JWS object can also be verified.
33
 */
34
final class Loader implements LoaderInterface
35
{
36
    use HasKeyChecker;
37
    use HasJWAManager;
38
    use HasJWKFinderManager;
39
    use HasCheckerManager;
40
    use HasPayloadConverter;
41
    use HasCompressionManager;
42
43
    /**
44
     * Loader constructor.
45
     *
46
     * @param \Jose\Algorithm\JWAManagerInterface            $jwa_manager
47
     * @param \Jose\Finder\JWKFinderManagerInterface         $jwk_finder_manager
48
     * @param \Jose\Payload\PayloadConverterManagerInterface $payload_converter_manager
49
     * @param \Jose\Compression\CompressionManagerInterface  $compression_manager
50
     * @param \Jose\Checker\CheckerManagerInterface          $checker_manager
51
     */
52
    public function __construct(
53
        JWAManagerInterface $jwa_manager,
54
        JWKFinderManagerInterface $jwk_finder_manager,
55
        PayloadConverterManagerInterface $payload_converter_manager,
56
        CompressionManagerInterface $compression_manager,
57
        CheckerManagerInterface $checker_manager)
58
    {
59
        $this->setJWAManager($jwa_manager);
60
        $this->setJWKFinderManager($jwk_finder_manager);
61
        $this->setPayloadConverter($payload_converter_manager);
62
        $this->setCompressionManager($compression_manager);
63
        $this->setCheckerManager($checker_manager);
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function load($input)
70
    {
71
        $json = Converter::convert($input, JSONSerializationModes::JSON_SERIALIZATION, false);
72
        if (is_array($json)) {
73
            if (array_key_exists('signatures', $json)) {
74
                return $this->loadSerializedJsonJWS($json, $input);
75
            }
76
            if (array_key_exists('recipients', $json)) {
77
                return $this->loadSerializedJsonJWE($json, $input);
78
            }
79
        }
80
        throw new \InvalidArgumentException('Unable to load the input');
81
    }
82
83
    /**
84
     * @param array  $data
85
     * @param string $input
86
     *
87
     * @return \Jose\Object\JWSInterface|\Jose\Object\JWSInterface[]
88
     */
89
    private function loadSerializedJsonJWS(array $data, $input)
90
    {
91
        $encoded_payload = isset($data['payload']) ? $data['payload'] : '';
92
        $payload = Base64Url::decode($encoded_payload);
93
94
        $jws = [];
95
        foreach ($data['signatures'] as $signature) {
96
            if (array_key_exists('protected', $signature)) {
97
                $encoded_protected_header = $signature['protected'];
98
                $protected_header = json_decode(Base64Url::decode($encoded_protected_header), true);
99
            } else {
100
                $encoded_protected_header = null;
101
                $protected_header = [];
102
            }
103
            $unprotected_header = isset($signature['header']) ? $signature['header'] : [];
104
105
            $result = $this->createJWS($encoded_protected_header, $encoded_payload, $protected_header, $unprotected_header, $payload, Base64Url::decode($signature['signature']));
106
            $result = $result->withInput($input);
107
            $jws[] = $result;
108
        }
109
110
        return count($jws) > 1 ? $jws : current($jws);
111
    }
112
113
    /**
114
     * @param string $encoded_protected_header
115
     * @param string $encoded_payload
116
     * @param array  $protected_header
117
     * @param array  $unprotected_header
118
     * @param string $payload
119
     * @param string $signature
120
     *
121
     * @throws \Exception
122
     *
123
     * @return \Jose\Object\JWSInterface
124
     */
125
    private function createJWS($encoded_protected_header, $encoded_payload, $protected_header, $unprotected_header, $payload, $signature)
126
    {
127
        $complete_header = array_merge($protected_header, $unprotected_header);
128
        $payload = $this->getPayloadConverter()->convertStringToPayload($complete_header, $payload);
129
        $jws = new JWS();
130
        $jws = $jws->withSignature($signature);
131
        $jws = $jws->withPayload($payload);
132
        $jws = $jws->withEncodedProtectedHeaders($encoded_protected_header);
133
        $jws = $jws->withEncodedPayload($encoded_payload);
134
        if (!empty($protected_header)) {
135
            $jws = $jws->withProtectedHeaders($protected_header);
136
        }
137
        if (!empty($unprotected_header)) {
138
            $jws = $jws->withUnprotectedHeaders($unprotected_header);
139
        }
140
141
        return $jws;
142
    }
143
144
    /**
145
     * @param array  $data
146
     * @param string $input
147
     *
148
     * @return \Jose\Object\JWEInterface|\Jose\Object\JWEInterface[]
149
     */
150
    private function loadSerializedJsonJWE(array $data, $input)
151
    {
152
        $result = [];
153
        foreach ($data['recipients'] as $recipient) {
154
            $encoded_protected_header = array_key_exists('protected', $data) ? $data['protected'] : '';
155
            $protected_header = empty($encoded_protected_header) ? [] : json_decode(Base64Url::decode($encoded_protected_header), true);
156
            $unprotected_header = array_key_exists('unprotected', $data) ? $data['unprotected'] : [];
157
            $header = array_key_exists('header', $recipient) ? $recipient['header'] : [];
158
159
            $jwe = new JWE();
160
            $jwe = $jwe->withAAD(array_key_exists('aad', $data) ? Base64Url::decode($data['aad']) : null);
161
            $jwe = $jwe->withCiphertext(Base64Url::decode($data['ciphertext']));
162
            $jwe = $jwe->withEncryptedKey(array_key_exists('encrypted_key', $recipient) ? Base64Url::decode($recipient['encrypted_key']) : null);
163
            $jwe = $jwe->withIV(array_key_exists('iv', $data) ? Base64Url::decode($data['iv']) : null);
164
            $jwe = $jwe->withTag(array_key_exists('tag', $data) ? Base64Url::decode($data['tag']) : null);
165
            $jwe = $jwe->withProtectedHeaders($protected_header);
166
            $jwe = $jwe->withEncodedProtectedHeaders($encoded_protected_header);
167
            $jwe = $jwe->withUnprotectedHeaders(array_merge($unprotected_header, $header));
168
            $jwe = $jwe->withInput($input);
169
            $result[] = $jwe;
170
        }
171
172
        return count($result) > 1 ? $result : current($result);
173
    }
174
}
175