4141use OCP \IConfig ;
4242use OCP \ILogger ;
4343use OCP \IUserSession ;
44+ use OCP \Lock \ILockingProvider ;
4445
4546class KeyManager {
4647
@@ -103,6 +104,11 @@ class KeyManager {
103104 */
104105 private $ util ;
105106
107+ /**
108+ * @var ILockingProvider
109+ */
110+ private $ lockingProvider ;
111+
106112 /**
107113 * @param IStorage $keyStorage
108114 * @param Crypt $crypt
@@ -119,14 +125,16 @@ public function __construct(
119125 IUserSession $ userSession ,
120126 Session $ session ,
121127 ILogger $ log ,
122- Util $ util
128+ Util $ util ,
129+ ILockingProvider $ lockingProvider
123130 ) {
124131 $ this ->util = $ util ;
125132 $ this ->session = $ session ;
126133 $ this ->keyStorage = $ keyStorage ;
127134 $ this ->crypt = $ crypt ;
128135 $ this ->config = $ config ;
129136 $ this ->log = $ log ;
137+ $ this ->lockingProvider = $ lockingProvider ;
130138
131139 $ this ->recoveryKeyId = $ this ->config ->getAppValue ('encryption ' ,
132140 'recoveryKeyId ' );
@@ -161,17 +169,24 @@ public function __construct(
161169 public function validateShareKey () {
162170 $ shareKey = $ this ->getPublicShareKey ();
163171 if (empty ($ shareKey )) {
164- $ keyPair = $ this ->crypt ->createKeyPair ();
165-
166- // Save public key
167- $ this ->keyStorage ->setSystemUserKey (
168- $ this ->publicShareKeyId . '.publicKey ' , $ keyPair ['publicKey ' ],
169- Encryption::ID );
170-
171- // Encrypt private key empty passphrase
172- $ encryptedKey = $ this ->crypt ->encryptPrivateKey ($ keyPair ['privateKey ' ], '' );
173- $ header = $ this ->crypt ->generateHeader ();
174- $ this ->setSystemPrivateKey ($ this ->publicShareKeyId , $ header . $ encryptedKey );
172+ $ this ->lockingProvider ->acquireLock ('encryption-generateSharedKey ' , ILockingProvider::LOCK_EXCLUSIVE , 'Encryption: shared key generation ' );
173+ try {
174+ $ keyPair = $ this ->crypt ->createKeyPair ();
175+
176+ // Save public key
177+ $ this ->keyStorage ->setSystemUserKey (
178+ $ this ->publicShareKeyId . '. ' . $ this ->publicKeyId , $ keyPair ['publicKey ' ],
179+ Encryption::ID );
180+
181+ // Encrypt private key empty passphrase
182+ $ encryptedKey = $ this ->crypt ->encryptPrivateKey ($ keyPair ['privateKey ' ], '' );
183+ $ header = $ this ->crypt ->generateHeader ();
184+ $ this ->setSystemPrivateKey ($ this ->publicShareKeyId , $ header . $ encryptedKey );
185+ } catch (\Throwable $ e ) {
186+ $ this ->lockingProvider ->releaseLock ('encryption-generateSharedKey ' , ILockingProvider::LOCK_EXCLUSIVE );
187+ throw $ e ;
188+ }
189+ $ this ->lockingProvider ->releaseLock ('encryption-generateSharedKey ' , ILockingProvider::LOCK_EXCLUSIVE );
175190 }
176191 }
177192
@@ -184,18 +199,36 @@ public function validateMasterKey() {
184199 }
185200
186201 $ publicMasterKey = $ this ->getPublicMasterKey ();
187- if (empty ($ publicMasterKey )) {
188- $ keyPair = $ this ->crypt ->createKeyPair ();
189-
190- // Save public key
191- $ this ->keyStorage ->setSystemUserKey (
192- $ this ->masterKeyId . '.publicKey ' , $ keyPair ['publicKey ' ],
193- Encryption::ID );
194-
195- // Encrypt private key with system password
196- $ encryptedKey = $ this ->crypt ->encryptPrivateKey ($ keyPair ['privateKey ' ], $ this ->getMasterKeyPassword (), $ this ->masterKeyId );
197- $ header = $ this ->crypt ->generateHeader ();
198- $ this ->setSystemPrivateKey ($ this ->masterKeyId , $ header . $ encryptedKey );
202+ $ privateMasterKey = $ this ->getPrivateMasterKey ();
203+
204+ if (empty ($ publicMasterKey ) && empty ($ privateMasterKey )) {
205+ // There could be a race condition here if two requests would trigger
206+ // the generation the second one would enter the key generation as long
207+ // as the first one didn't write the key to the keystorage yet
208+ $ this ->lockingProvider ->acquireLock ('encryption-generateMasterKey ' , ILockingProvider::LOCK_EXCLUSIVE , 'Encryption: master key generation ' );
209+ try {
210+ $ keyPair = $ this ->crypt ->createKeyPair ();
211+
212+ // Save public key
213+ $ this ->keyStorage ->setSystemUserKey (
214+ $ this ->masterKeyId . '. ' . $ this ->publicKeyId , $ keyPair ['publicKey ' ],
215+ Encryption::ID );
216+
217+ // Encrypt private key with system password
218+ $ encryptedKey = $ this ->crypt ->encryptPrivateKey ($ keyPair ['privateKey ' ], $ this ->getMasterKeyPassword (), $ this ->masterKeyId );
219+ $ header = $ this ->crypt ->generateHeader ();
220+ $ this ->setSystemPrivateKey ($ this ->masterKeyId , $ header . $ encryptedKey );
221+ } catch (\Throwable $ e ) {
222+ $ this ->lockingProvider ->releaseLock ('encryption-generateMasterKey ' , ILockingProvider::LOCK_EXCLUSIVE );
223+ throw $ e ;
224+ }
225+ $ this ->lockingProvider ->releaseLock ('encryption-generateMasterKey ' , ILockingProvider::LOCK_EXCLUSIVE );
226+ } elseif (empty ($ publicMasterKey )) {
227+ $ this ->log ->error ('A private master key is available but the public key could not be found. This should never happen. ' );
228+ return ;
229+ } elseif (empty ($ privateMasterKey )) {
230+ $ this ->log ->error ('A public master key is available but the private key could not be found. This should never happen. ' );
231+ return ;
199232 }
200233
201234 if (!$ this ->session ->isPrivateKeySet ()) {
@@ -222,7 +255,7 @@ public function recoveryKeyExists() {
222255 * @return string
223256 */
224257 public function getRecoveryKey () {
225- return $ this ->keyStorage ->getSystemUserKey ($ this ->recoveryKeyId . '.publicKey ' , Encryption::ID );
258+ return $ this ->keyStorage ->getSystemUserKey ($ this ->recoveryKeyId . '. ' . $ this -> publicKeyId , Encryption::ID );
226259 }
227260
228261 /**
@@ -239,7 +272,7 @@ public function getRecoveryKeyId() {
239272 * @return bool
240273 */
241274 public function checkRecoveryPassword ($ password ) {
242- $ recoveryKey = $ this ->keyStorage ->getSystemUserKey ($ this ->recoveryKeyId . '.privateKey ' , Encryption::ID );
275+ $ recoveryKey = $ this ->keyStorage ->getSystemUserKey ($ this ->recoveryKeyId . '. ' . $ this -> privateKeyId , Encryption::ID );
243276 $ decryptedRecoveryKey = $ this ->crypt ->decryptPrivateKey ($ recoveryKey , $ password );
244277
245278 if ($ decryptedRecoveryKey ) {
@@ -251,7 +284,7 @@ public function checkRecoveryPassword($password) {
251284 /**
252285 * @param string $uid
253286 * @param string $password
254- * @param string $keyPair
287+ * @param array $keyPair
255288 * @return bool
256289 */
257290 public function storeKeyPair ($ uid , $ password , $ keyPair ) {
@@ -277,7 +310,7 @@ public function storeKeyPair($uid, $password, $keyPair) {
277310 public function setRecoveryKey ($ password , $ keyPair ) {
278311 // Save Public Key
279312 $ this ->keyStorage ->setSystemUserKey ($ this ->getRecoveryKeyId ().
280- '.publicKey ' ,
313+ '. ' . $ this -> publicKeyId ,
281314 $ keyPair ['publicKey ' ],
282315 Encryption::ID );
283316
@@ -435,7 +468,7 @@ public function getFileKey($path, $uid) {
435468 // use public share key for public links
436469 $ uid = $ this ->getPublicShareKeyId ();
437470 $ shareKey = $ this ->getShareKey ($ path , $ uid );
438- $ privateKey = $ this ->keyStorage ->getSystemUserKey ($ this ->publicShareKeyId . '.privateKey ' , Encryption::ID );
471+ $ privateKey = $ this ->keyStorage ->getSystemUserKey ($ this ->publicShareKeyId . '. ' . $ this -> privateKeyId , Encryption::ID );
439472 $ privateKey = $ this ->crypt ->decryptPrivateKey ($ privateKey );
440473 } else {
441474 $ shareKey = $ this ->getShareKey ($ path , $ uid );
@@ -578,7 +611,7 @@ public function getPublicShareKeyId() {
578611 * @return string
579612 */
580613 public function getPublicShareKey () {
581- return $ this ->keyStorage ->getSystemUserKey ($ this ->publicShareKeyId . '.publicKey ' , Encryption::ID );
614+ return $ this ->keyStorage ->getSystemUserKey ($ this ->publicShareKeyId . '. ' . $ this -> publicKeyId , Encryption::ID );
582615 }
583616
584617 /**
@@ -718,6 +751,15 @@ public function getMasterKeyId() {
718751 * @return string
719752 */
720753 public function getPublicMasterKey () {
721- return $ this ->keyStorage ->getSystemUserKey ($ this ->masterKeyId . '.publicKey ' , Encryption::ID );
754+ return $ this ->keyStorage ->getSystemUserKey ($ this ->masterKeyId . '. ' . $ this ->publicKeyId , Encryption::ID );
755+ }
756+
757+ /**
758+ * get public master key
759+ *
760+ * @return string
761+ */
762+ public function getPrivateMasterKey () {
763+ return $ this ->keyStorage ->getSystemUserKey ($ this ->masterKeyId . '. ' . $ this ->privateKeyId , Encryption::ID );
722764 }
723765}
0 commit comments