Skip to content

Commit

Permalink
signatories
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <[email protected]>
  • Loading branch information
ArtificialOwl committed Jun 19, 2024
1 parent 42fa007 commit a6481e3
Show file tree
Hide file tree
Showing 24 changed files with 1,002 additions and 0 deletions.
14 changes: 14 additions & 0 deletions lib/private/OCM/OCMSignatoryManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace OC\OCM;

use OCP\Security\Signature\ISignatoryManager;

class OCMSignatoryManager implements ISignatoryManager {

Check failure on line 9 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MethodSignatureMismatch

lib/private/OCM/OCMSignatoryManager.php:9:7: MethodSignatureMismatch: Method OC\OCM\OCMSignatoryManager::generateSignatory with return type 'OC\OCM\ISignatory' is different to return type 'OCP\Security\Signature\Model\ISignatory' of inherited method OCP\Security\Signature\ISignatoryManager::generateSignatory (see https://psalm.dev/042)

Check failure

Code scanning / Psalm

MethodSignatureMismatch Error

Method OC\OCM\OCMSignatoryManager::generateSignatory with return type 'OC\OCM\ISignatory' is different to return type 'OCP\Security\Signature\Model\ISignatory' of inherited method OCP\Security\Signature\ISignatoryManager::generateSignatory

public function generateSignatory(IIncomingSignedRequest $signedRequest): ISignatory {

Check failure on line 11 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedClass

lib/private/OCM/OCMSignatoryManager.php:11:36: UndefinedClass: Class, interface or enum named OC\OCM\IIncomingSignedRequest does not exist (see https://psalm.dev/019)

Check failure on line 11 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MethodSignatureMismatch

lib/private/OCM/OCMSignatoryManager.php:11:59: MethodSignatureMismatch: Argument 1 of OC\OCM\OCMSignatoryManager::generateSignatory has wrong type 'OC\OCM\IIncomingSignedRequest', expecting 'OCP\Security\Signature\Model\IIncomingSignedRequest' as defined by OCP\Security\Signature\ISignatoryManager::generateSignatory (see https://psalm.dev/042)

Check failure on line 11 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

ImplementedParamTypeMismatch

lib/private/OCM/OCMSignatoryManager.php:11:59: ImplementedParamTypeMismatch: Argument 1 of OC\OCM\OCMSignatoryManager::generateSignatory has wrong type 'OC\OCM\IIncomingSignedRequest', expecting 'OCP\Security\Signature\Model\IIncomingSignedRequest' as defined by OCP\Security\Signature\ISignatoryManager::generateSignatory (see https://psalm.dev/199)

Check failure on line 11 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedClass

lib/private/OCM/OCMSignatoryManager.php:11:76: UndefinedClass: Class, interface or enum named OC\OCM\ISignatory does not exist (see https://psalm.dev/019)

Check failure on line 11 in lib/private/OCM/OCMSignatoryManager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

InvalidReturnType

lib/private/OCM/OCMSignatoryManager.php:11:76: InvalidReturnType: Not all code paths of OC\OCM\OCMSignatoryManager::generateSignatory end in a return statement, return type OC\OCM\ISignatory expected (see https://psalm.dev/011)

Check failure

Code scanning / Psalm

UndefinedClass Error

Class, interface or enum named OC\OCM\IIncomingSignedRequest does not exist

Check failure

Code scanning / Psalm

MethodSignatureMismatch Error

Argument 1 of OC\OCM\OCMSignatoryManager::generateSignatory has wrong type 'OC\OCM\IIncomingSignedRequest', expecting 'OCP\Security\Signature\Model\IIncomingSignedRequest' as defined by OCP\Security\Signature\ISignatoryManager::generateSignatory

Check failure

Code scanning / Psalm

ImplementedParamTypeMismatch Error

Argument 1 of OC\OCM\OCMSignatoryManager::generateSignatory has wrong type 'OC\OCM\IIncomingSignedRequest', expecting 'OCP\Security\Signature\Model\IIncomingSignedRequest' as defined by OCP\Security\Signature\ISignatoryManager::generateSignatory

Check failure

Code scanning / Psalm

UndefinedClass Error

Class, interface or enum named OC\OCM\ISignatory does not exist

Check failure

Code scanning / Psalm

InvalidReturnType Error

Not all code paths of OC\OCM\OCMSignatoryManager::generateSignatory end in a return statement, return type OC\OCM\ISignatory expected

}
}
85 changes: 85 additions & 0 deletions lib/private/Security/PublicPrivateKeyPairs/KeyPairManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

namespace OC\Security\PublicPrivateKeyPairs;

use OC\Security\PublicPrivateKeyPairs\Model\KeyPair;
use OCP\Security\PublicPrivateKeyPairs\IKeyPairManager;
use OCP\Security\PublicPrivateKeyPairs\Model\IKeyPair;
use OCP\IAppConfig;

class KeyPairManager implements IKeyPairManager {
public function __construct(
private readonly IAppConfig $appConfig,
) {
}

public function getKeyPair(string $app, string $name, array $options = []): IKeyPair {
if (!$this->appConfig->hasKey($app, $name, lazy: true)) {
return $this->generateKeyPair($app, $name, $options);
}

$stored = $this->appConfig->getValueArray($app, $name, lazy: true);
if (!array_key_exists('public', $stored) ||
!array_key_exists('private', $stored)) {
return $this->generateKeyPair($app, $name);
}

$keyPair = new KeyPair($app, $name);
$keyPair->setPublicKey($stored['public'])
->setPrivateKey($stored['private']);

return $keyPair;
}

public function deleteKeyPair(string $app, string $name): void {
}

public function testKeyPair(IKeyPair $keyPair): bool {
// encrypt using private key
// decrypt using public key
// compare
return false;
}

private function generateKeyPair(string $app, string $name, array $options = []): IKeyPair {
$keyPair = new KeyPair($app, $name);

[$publicKey, $privateKey] = $this->generateKeys($options);
$keyPair->setPublicKey($publicKey);
$keyPair->setPrivateKey($privateKey);

$this->appConfig->setValueArray(
$app, 'security.keypair.' . $name,
[
'public' => $keyPair->getPublicKey(),
'private' => $keyPair->getPrivateKey()
],
lazy: true,
sensitive: true
);

return $keyPair;
}

/**
* @param array $options
*
* @return array
*/
private function generateKeys(array $options = []):array {
$res = openssl_pkey_new(
[
'digest_alg' => $options['algorithm'] ?? 'rsa',
'private_key_bits' => $options['bits'] ?? 2048,
'private_key_type' => $options['type'] ?? OPENSSL_KEYTYPE_RSA,
]
);

openssl_pkey_export($res, $privateKey);
$publicKey = openssl_pkey_get_details($res)['key'];

return [$publicKey, $privateKey];
}
}
44 changes: 44 additions & 0 deletions lib/private/Security/PublicPrivateKeyPairs/Model/KeyPair.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

namespace OC\Security\PublicPrivateKeyPairs\Model;

use OCP\Security\PublicPrivateKeyPairs\Model\IKeyPair;

class KeyPair implements IKeyPair {
private string $publicKey = '';
private string $privateKey = '';

public function __construct(
private readonly string $app,
private readonly string $name
) {
}

public function getApp(): string {
return $this->app;
}

public function getName(): string {
return $this->name;
}

public function setPublicKey(string $publicKey): self {
$this->publicKey = $publicKey;
return $this;
}

public function getPublicKey(): string {
return $this->publicKey;
}

public function setPrivateKey(string $privateKey): self {
$this->privateKey = $privateKey;
return $this;
}

public function getPrivateKey(): string {
return $this->privateKey;
}
}
89 changes: 89 additions & 0 deletions lib/private/Security/Signature/Model/IncomingSignedRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\Security\Signature\Model;

use JsonSerializable;
use OCP\IRequest;
use OCP\Security\Signature\Exceptions\IncomingRequestNotFoundException;
use OCP\Security\Signature\Model\IIncomingSignedRequest;

class IncomingSignedRequest extends SignedRequest
implements
IIncomingSignedRequest,
JsonSerializable
{
private ?IRequest $request = null;
private int $time = 0;
private string $origin;
private string $host;
private string $estimatedSignature;

public function setRequest(IRequest $request): IIncomingSignedRequest {
$this->request = $request;
return $this;
}

public function getRequest(): IRequest {
if ($this->request === null) {
throw new IncomingRequestNotFoundException();
}
return $this->request;
}

public function setTime(int $time): IIncomingSignedRequest {
$this->time = $time;
return $this;
}

public function getTime(): int {
return $this->time;
}

public function setOrigin(string $origin): IIncomingSignedRequest {
$this->origin = $origin;
return $this;
}

public function getOrigin(): string {
return $this->origin;
}

/** local address */
public function setHost(string $host): IIncomingSignedRequest {
$this->host = $host;
return $this;
}

public function getHost(): string {
return $this->host;
}

public function setEstimatedSignature(string $signature): IIncomingSignedRequest {
$this->estimatedSignature = $signature;
return $this;
}

public function getEstimatedSignature(): string {
return $this->estimatedSignature;
}

public function jsonSerialize(): array {
return array_merge(
parent::jsonSerialize(),
[
'body' => $this->getBody(),
'time' => $this->getTime(),
'incomingRequest' => $this->request ?? false,
'origin' => $this->getOrigin(),
'host' => $this->getHost(),
'estimatedSignature' => $this->getEstimatedSignature(),
]
);
}
}
62 changes: 62 additions & 0 deletions lib/private/Security/Signature/Model/OutgoingSignedRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\Security\Signature\Model;

use JsonSerializable;
use OCP\IRequest;
use OCP\Security\Signature\Model\IOutgoingSignedRequest;

class OutgoingSignedRequest extends SignedRequest
implements
IOutgoingSignedRequest,
JsonSerializable
{
private IRequest $request;
private string $host = '';
private string $clearSignature = '';

public function setRequest(IRequest $request): IOutgoingSignedRequest {
$this->request = $request;
return $this;
}

public function getRequest(): IRequest {
return $this->request;
}

/** remote address */
public function setHost(string $host): IOutgoingSignedRequest {
$this->host = $host;
return $this;
}

public function getHost(): string {
return $this->host;
}

public function setClearSignature(string $estimated): self {
$this->clearSignature = $estimated;
return $this;
}

public function getClearSignature(): string {
return $this->clearSignature;
}

public function jsonSerialize(): array {
return array_merge(
parent::jsonSerialize(),
[
'outgoingRequest' => $this->request ?? false,

Check failure on line 56 in lib/private/Security/Signature/Model/OutgoingSignedRequest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

RedundantPropertyInitializationCheck

lib/private/Security/Signature/Model/OutgoingSignedRequest.php:56:26: RedundantPropertyInitializationCheck: Property $this->request with type OCP\IRequest should already be set in the constructor (see https://psalm.dev/261)

Check failure on line 56 in lib/private/Security/Signature/Model/OutgoingSignedRequest.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

RedundantPropertyInitializationCheck

lib/private/Security/Signature/Model/OutgoingSignedRequest.php:56:44: RedundantPropertyInitializationCheck: Property $this->request with type OCP\IRequest should already be set in the constructor (see https://psalm.dev/261)

Check failure

Code scanning / Psalm

RedundantPropertyInitializationCheck Error

Property $this->request with type OCP\IRequest should already be set in the constructor

Check failure

Code scanning / Psalm

RedundantPropertyInitializationCheck Error

Property $this->request with type OCP\IRequest should already be set in the constructor
'host' => $this->getHost(),
'clearSignature' => $this->getClearSignature(),
]
);
}
}
36 changes: 36 additions & 0 deletions lib/private/Security/Signature/Model/Signatory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\Security\Signature\Model;

use JsonSerializable;
use OCP\Security\Signature\Model\ISignatory;

class Signatory implements ISignatory, JsonSerializable {
public function __construct(
private readonly string $publicKey,
private readonly string $privateKey = ''
) {
}

public function getPublicKey(): string {
return $this->publicKey;
}

public function getPrivateKey(): string {
return $this->privateKey;
}

public function jsonSerialize(): array {
return [
'publicKey' => $this->getPublicKey(),
'publicKeyChecksum' => ($this->getPublicKey() !== '') ? sha1($this->getPublicKey()) : false,
'privateKeyChecksum' => ($this->getPrivateKey() !== '') ? sha1($this->getPrivateKey()) : false
];
}
}
Loading

0 comments on commit a6481e3

Please sign in to comment.