Skip to content

Commit 5b3471f

Browse files
ArtificialOwlPVince81
authored andcommitted
confirm identity proof key checksum
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
1 parent 88b6644 commit 5b3471f

File tree

5 files changed

+120
-13
lines changed

5 files changed

+120
-13
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1496,6 +1496,7 @@
14961496
'OC\\Security\\FeaturePolicy\\FeaturePolicy' => $baseDir . '/lib/private/Security/FeaturePolicy/FeaturePolicy.php',
14971497
'OC\\Security\\FeaturePolicy\\FeaturePolicyManager' => $baseDir . '/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php',
14981498
'OC\\Security\\Hasher' => $baseDir . '/lib/private/Security/Hasher.php',
1499+
'OC\\Security\\IdentityProof\\Exception\\IdentityProofKeySumException' => $baseDir . '/lib/private/Security/IdentityProof/Exception/IdentityProofKeySumException.php',
14991500
'OC\\Security\\IdentityProof\\Key' => $baseDir . '/lib/private/Security/IdentityProof/Key.php',
15001501
'OC\\Security\\IdentityProof\\Manager' => $baseDir . '/lib/private/Security/IdentityProof/Manager.php',
15011502
'OC\\Security\\IdentityProof\\Signer' => $baseDir . '/lib/private/Security/IdentityProof/Signer.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
15291529
'OC\\Security\\FeaturePolicy\\FeaturePolicy' => __DIR__ . '/../../..' . '/lib/private/Security/FeaturePolicy/FeaturePolicy.php',
15301530
'OC\\Security\\FeaturePolicy\\FeaturePolicyManager' => __DIR__ . '/../../..' . '/lib/private/Security/FeaturePolicy/FeaturePolicyManager.php',
15311531
'OC\\Security\\Hasher' => __DIR__ . '/../../..' . '/lib/private/Security/Hasher.php',
1532+
'OC\\Security\\IdentityProof\\Exception\\IdentityProofKeySumException' => __DIR__ . '/../../..' . '/lib/private/Security/IdentityProof/Exception/IdentityProofKeySumException.php',
15321533
'OC\\Security\\IdentityProof\\Key' => __DIR__ . '/../../..' . '/lib/private/Security/IdentityProof/Key.php',
15331534
'OC\\Security\\IdentityProof\\Manager' => __DIR__ . '/../../..' . '/lib/private/Security/IdentityProof/Manager.php',
15341535
'OC\\Security\\IdentityProof\\Signer' => __DIR__ . '/../../..' . '/lib/private/Security/IdentityProof/Signer.php',
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2022, Maxence Lange <maxence@artificial-owl.com>
7+
*
8+
* @author Maxence Lange <maxence@artificial-owl.com>
9+
*
10+
* @license GNU AGPL version 3 or any later version
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU Affero General Public License as
14+
* published by the Free Software Foundation, either version 3 of the
15+
* License, or (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU Affero General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU Affero General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
namespace OC\Security\IdentityProof\Exception;
27+
28+
class IdentityProofKeySumException extends \Exception {
29+
}
30+

lib/private/Security/IdentityProof/Key.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*
88
* @author Lukas Reschke <lukas@statuscode.ch>
99
* @author Roeland Jago Douma <roeland@famdouma.nl>
10+
* @author Maxence Lange <maxence@artificial-owl.com>
1011
*
1112
* @license GNU AGPL version 3 or any later version
1213
*
@@ -48,4 +49,8 @@ public function getPrivate(): string {
4849
public function getPublic(): string {
4950
return $this->publicKey;
5051
}
52+
53+
public function getSum(): string {
54+
return hash('sha512', $this->getPublic() . '.' . $this->getPrivate());
55+
}
5156
}

lib/private/Security/IdentityProof/Manager.php

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* @author Joas Schilling <coding@schilljs.com>
1111
* @author Lukas Reschke <lukas@statuscode.ch>
1212
* @author Roeland Jago Douma <roeland@famdouma.nl>
13+
* @author Maxence Lange <maxence@artificial-owl.com>
1314
*
1415
* @license GNU AGPL version 3 or any later version
1516
*
@@ -27,16 +28,24 @@
2728
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2829
*
2930
*/
31+
3032
namespace OC\Security\IdentityProof;
3133

3234
use OC\Files\AppData\Factory;
35+
use OC\Security\IdentityProof\Exception\IdentityProofKeySumException;
3336
use OCP\Files\IAppData;
37+
use OCP\Files\NotFoundException;
38+
use OCP\Files\NotPermittedException;
3439
use OCP\IConfig;
3540
use OCP\IUser;
41+
use OCP\PreConditionNotMetException;
3642
use OCP\Security\ICrypto;
3743
use Psr\Log\LoggerInterface;
44+
use RuntimeException;
3845

3946
class Manager {
47+
public const SUM_PREFERENCES_KEY = 'identity_proof_key_sum';
48+
4049
/** @var IAppData */
4150
private $appData;
4251
/** @var ICrypto */
@@ -61,7 +70,7 @@ public function __construct(Factory $appDataFactory,
6170
* In a separate function for unit testing purposes.
6271
*
6372
* @return array [$publicKey, $privateKey]
64-
* @throws \RuntimeException
73+
* @throws RuntimeException
6574
*/
6675
protected function generateKeyPair(): array {
6776
$config = [
@@ -74,12 +83,12 @@ protected function generateKeyPair(): array {
7483

7584
if ($res === false) {
7685
$this->logOpensslError();
77-
throw new \RuntimeException('OpenSSL reported a problem');
86+
throw new RuntimeException('OpenSSL reported a problem');
7887
}
7988

8089
if (openssl_pkey_export($res, $privateKey, null, $config) === false) {
8190
$this->logOpensslError();
82-
throw new \RuntimeException('OpenSSL reported a problem');
91+
throw new RuntimeException('OpenSSL reported a problem');
8392
}
8493

8594
// Extract the public key from $res to $pubKey
@@ -94,8 +103,10 @@ protected function generateKeyPair(): array {
94103
* Note: If a key already exists it will be overwritten
95104
*
96105
* @param string $id key id
106+
*
97107
* @return Key
98-
* @throws \RuntimeException
108+
* @throws NotFoundException
109+
* @throws NotPermittedException
99110
*/
100111
protected function generateKey(string $id): Key {
101112
[$publicKey, $privateKey] = $this->generateKeyPair();
@@ -109,54 +120,113 @@ protected function generateKey(string $id): Key {
109120
$folder->newFile('private')
110121
->putContent($this->crypto->encrypt($privateKey));
111122
$folder->newFile('public')
112-
->putContent($publicKey);
123+
->putContent($publicKey);
113124

114125
return new Key($publicKey, $privateKey);
115126
}
116127

117128
/**
118129
* Get key for a specific id
130+
* if $userId is set, a checksum of the key will be stored for future comparison
119131
*
120132
* @param string $id
133+
* @param string $userId
134+
*
121135
* @return Key
122-
* @throws \RuntimeException
136+
* @throws NotFoundException
137+
* @throws NotPermittedException
138+
* @throws PreConditionNotMetException
123139
*/
124-
protected function retrieveKey(string $id): Key {
140+
protected function retrieveKey(string $id, string $userId = ''): Key {
125141
try {
126142
$folder = $this->appData->getFolder($id);
127143
$privateKey = $this->crypto->decrypt(
128144
$folder->getFile('private')->getContent()
129145
);
130146
$publicKey = $folder->getFile('public')->getContent();
131-
return new Key($publicKey, $privateKey);
147+
$key = new Key($publicKey, $privateKey);
148+
149+
$this->confirmSum($key, $userId);
132150
} catch (\Exception $e) {
133-
return $this->generateKey($id);
151+
$key = $this->generateKey($id);
152+
$this->generateKeySum($key, $userId);
134153
}
154+
155+
return $key;
135156
}
136157

158+
159+
/**
160+
* @param Key $key
161+
* @param string $userId
162+
*
163+
* @throws IdentityProofKeySumException
164+
* @throws PreConditionNotMetException
165+
*/
166+
protected function confirmSum(Key $key, string $userId): void {
167+
if ($userId === '') {
168+
$knownSum = $this->config->getAppValue('core', self::SUM_PREFERENCES_KEY, '');
169+
} else {
170+
$knownSum = $this->config->getUserValue($userId, 'core', self::SUM_PREFERENCES_KEY, '');
171+
}
172+
173+
if ($knownSum === '') { // sum is not known, generate a new one
174+
$this->generateKeySum($key, $userId);
175+
}
176+
177+
if ($knownSum !== $key->getSum()) {
178+
throw new IdentityProofKeySumException();
179+
}
180+
}
181+
182+
183+
/**
184+
* @param Key $key
185+
* @param string $userId
186+
*
187+
* @return void
188+
* @throws PreConditionNotMetException
189+
*/
190+
public function generateKeySum(Key $key, string $userId): void {
191+
if ($userId === '') {
192+
$this->config->setAppValue('core', self::SUM_PREFERENCES_KEY, $key->getSum());
193+
} else {
194+
$this->config->setUserValue($userId, 'core', self::SUM_PREFERENCES_KEY, $key->getSum());
195+
}
196+
197+
}
198+
199+
137200
/**
138201
* Get public and private key for $user
139202
*
140203
* @param IUser $user
204+
*
141205
* @return Key
142-
* @throws \RuntimeException
206+
* @throws NotFoundException
207+
* @throws NotPermittedException
208+
* @throws PreConditionNotMetException
143209
*/
144210
public function getKey(IUser $user): Key {
145211
$uid = $user->getUID();
146-
return $this->retrieveKey('user-' . $uid);
212+
213+
return $this->retrieveKey('user-' . $uid, $uid);
147214
}
148215

149216
/**
150217
* Get instance wide public and private key
151218
*
152219
* @return Key
153-
* @throws \RuntimeException
220+
* @throws NotFoundException
221+
* @throws NotPermittedException
222+
* @throws PreConditionNotMetException
154223
*/
155224
public function getSystemKey(): Key {
156225
$instanceId = $this->config->getSystemValue('instanceid', null);
157226
if ($instanceId === null) {
158-
throw new \RuntimeException('no instance id!');
227+
throw new RuntimeException('no instance id!');
159228
}
229+
160230
return $this->retrieveKey('system-' . $instanceId);
161231
}
162232

0 commit comments

Comments
 (0)