diff options
Diffstat (limited to 'lib/unstable/Security/Signature')
-rw-r--r-- | lib/unstable/Security/Signature/Enum/SignatoryStatus.php (renamed from lib/unstable/Security/Signature/Model/SignatoryStatus.php) | 2 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/Enum/SignatoryType.php (renamed from lib/unstable/Security/Signature/Model/SignatoryType.php) | 6 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php (renamed from lib/unstable/Security/Signature/SignatureAlgorithm.php) | 2 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/IIncomingSignedRequest.php (renamed from lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php) | 14 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/IOutgoingSignedRequest.php (renamed from lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php) | 33 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/ISignatoryManager.php | 10 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/ISignatureManager.php | 8 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/ISignedRequest.php (renamed from lib/unstable/Security/Signature/Model/ISignedRequest.php) | 44 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/Model/ISignatory.php | 160 | ||||
-rw-r--r-- | lib/unstable/Security/Signature/Model/Signatory.php | 165 |
10 files changed, 235 insertions, 209 deletions
diff --git a/lib/unstable/Security/Signature/Model/SignatoryStatus.php b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php index 4174102beae..9c77cf9bbc2 100644 --- a/lib/unstable/Security/Signature/Model/SignatoryStatus.php +++ b/lib/unstable/Security/Signature/Enum/SignatoryStatus.php @@ -6,7 +6,7 @@ declare(strict_types=1); * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature\Model; +namespace NCU\Security\Signature\Enum; /** * current status of signatory. is it trustable or not ? diff --git a/lib/unstable/Security/Signature/Model/SignatoryType.php b/lib/unstable/Security/Signature/Enum/SignatoryType.php index 652bee2a970..86a766d2aa0 100644 --- a/lib/unstable/Security/Signature/Model/SignatoryType.php +++ b/lib/unstable/Security/Signature/Enum/SignatoryType.php @@ -3,15 +3,15 @@ declare(strict_types=1); /** - * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature\Model; +namespace NCU\Security\Signature\Enum; /** * type of link between local and remote instance * - * - FORGIVABLE = the keypair can be deleted and refreshed anytime and silently + * - FORGIVABLE = the keypair can be deleted and refreshed anytime; silently * - REFRESHABLE = the keypair can be refreshed but a notice will be generated * - TRUSTED = any changes of keypair will require human interaction, warning will be issued * - STATIC = error will be issued on conflict, assume keypair cannot be reset. diff --git a/lib/unstable/Security/Signature/SignatureAlgorithm.php b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php index c0a5a0c6c7a..94996d17bd5 100644 --- a/lib/unstable/Security/Signature/SignatureAlgorithm.php +++ b/lib/unstable/Security/Signature/Enum/SignatureAlgorithm.php @@ -6,7 +6,7 @@ declare(strict_types=1); * SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature; +namespace NCU\Security\Signature\Enum; /** * list of available algorithm when signing payload diff --git a/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php b/lib/unstable/Security/Signature/IIncomingSignedRequest.php index 3e2ebb22a5f..7f37570533f 100644 --- a/lib/unstable/Security/Signature/Model/IIncomingSignedRequest.php +++ b/lib/unstable/Security/Signature/IIncomingSignedRequest.php @@ -6,10 +6,11 @@ declare(strict_types=1); * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature\Model; +namespace NCU\Security\Signature; +use NCU\Security\Signature\Exceptions\SignatoryNotFoundException; use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException; -use NCU\Security\Signature\ISignatureManager; +use NCU\Security\Signature\Exceptions\SignatureException; use OCP\IRequest; /** @@ -57,4 +58,13 @@ interface IIncomingSignedRequest extends ISignedRequest { * @since 31.0.0 */ public function getKeyId(): string; + + /** + * confirm the current signed request's identity is correct + * + * @throws SignatureException + * @throws SignatoryNotFoundException + * @since 31.0.0 + */ + public function verify(): void; } diff --git a/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php index 3c9445af745..de2ab7e276d 100644 --- a/lib/unstable/Security/Signature/Model/IOutgoingSignedRequest.php +++ b/lib/unstable/Security/Signature/IOutgoingSignedRequest.php @@ -6,10 +6,11 @@ declare(strict_types=1); * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature\Model; +namespace NCU\Security\Signature; -use NCU\Security\Signature\ISignatureManager; -use NCU\Security\Signature\SignatureAlgorithm; +use NCU\Security\Signature\Enum\SignatureAlgorithm; +use NCU\Security\Signature\Exceptions\SignatoryException; +use NCU\Security\Signature\Exceptions\SignatoryNotFoundException; /** * extends ISignedRequest to add info requested at the generation of the signature @@ -23,10 +24,10 @@ interface IOutgoingSignedRequest extends ISignedRequest { * set the host of the recipient of the request. * * @param string $host - * @return IOutgoingSignedRequest + * @return self * @since 31.0.0 */ - public function setHost(string $host): IOutgoingSignedRequest; + public function setHost(string $host): self; /** * get the host of the recipient of the request. @@ -44,10 +45,10 @@ interface IOutgoingSignedRequest extends ISignedRequest { * @param string $key * @param string|int|float $value * - * @return IOutgoingSignedRequest + * @return self * @since 31.0.0 */ - public function addHeader(string $key, string|int|float $value): IOutgoingSignedRequest; + public function addHeader(string $key, string|int|float $value): self; /** * returns list of headers value that will be added to the base request @@ -62,10 +63,10 @@ interface IOutgoingSignedRequest extends ISignedRequest { * * @param list<string> $list * - * @return IOutgoingSignedRequest + * @return self * @since 31.0.0 */ - public function setHeaderList(array $list): IOutgoingSignedRequest; + public function setHeaderList(array $list): self; /** * returns ordered list of used headers in the Signature @@ -80,10 +81,10 @@ interface IOutgoingSignedRequest extends ISignedRequest { * * @param SignatureAlgorithm $algorithm * - * @return IOutgoingSignedRequest + * @return self * @since 31.0.0 */ - public function setAlgorithm(SignatureAlgorithm $algorithm): IOutgoingSignedRequest; + public function setAlgorithm(SignatureAlgorithm $algorithm): self; /** * returns the algorithm set to sign the signature @@ -92,4 +93,14 @@ interface IOutgoingSignedRequest extends ISignedRequest { * @since 31.0.0 */ public function getAlgorithm(): SignatureAlgorithm; + + /** + * sign outgoing request providing a certificate that it emanate from this instance + * + * @return self + * @throws SignatoryException + * @throws SignatoryNotFoundException + * @since 31.0.0 + */ + public function sign(): self; } diff --git a/lib/unstable/Security/Signature/ISignatoryManager.php b/lib/unstable/Security/Signature/ISignatoryManager.php index 19ba83a4206..20133de4c9c 100644 --- a/lib/unstable/Security/Signature/ISignatoryManager.php +++ b/lib/unstable/Security/Signature/ISignatoryManager.php @@ -8,7 +8,7 @@ declare(strict_types=1); */ namespace NCU\Security\Signature; -use NCU\Security\Signature\Model\ISignatory; +use NCU\Security\Signature\Model\Signatory; /** * ISignatoryManager contains a group of method that will help @@ -51,10 +51,10 @@ interface ISignatoryManager { * * Used to sign outgoing request * - * @return ISignatory + * @return Signatory * @since 31.0.0 */ - public function getLocalSignatory(): ISignatory; + public function getLocalSignatory(): Signatory; /** * retrieve details and generate signatory from remote instance. @@ -64,8 +64,8 @@ interface ISignatoryManager { * * @param string $remote * - * @return ISignatory|null must be NULL if no signatory is found + * @return Signatory|null must be NULL if no signatory is found * @since 31.0.0 */ - public function getRemoteSignatory(string $remote): ?ISignatory; + public function getRemoteSignatory(string $remote): ?Signatory; } diff --git a/lib/unstable/Security/Signature/ISignatureManager.php b/lib/unstable/Security/Signature/ISignatureManager.php index 1969b970aa6..c614a16cd92 100644 --- a/lib/unstable/Security/Signature/ISignatureManager.php +++ b/lib/unstable/Security/Signature/ISignatureManager.php @@ -13,9 +13,7 @@ use NCU\Security\Signature\Exceptions\IncomingRequestException; use NCU\Security\Signature\Exceptions\SignatoryNotFoundException; use NCU\Security\Signature\Exceptions\SignatureException; use NCU\Security\Signature\Exceptions\SignatureNotFoundException; -use NCU\Security\Signature\Model\IIncomingSignedRequest; -use NCU\Security\Signature\Model\IOutgoingSignedRequest; -use NCU\Security\Signature\Model\ISignatory; +use NCU\Security\Signature\Model\Signatory; /** * ISignatureManager is a service integrated to core that provide tools @@ -99,11 +97,11 @@ interface ISignatureManager { * @param string $host remote host * @param string $account linked account, should be used when multiple signature can exist for the same host * - * @return ISignatory + * @return Signatory * @throws SignatoryNotFoundException if entry does not exist in local database * @since 31.0.0 */ - public function searchSignatory(string $host, string $account = ''): ISignatory; + public function getSignatory(string $host, string $account = ''): Signatory; /** * returns a fully formatted keyId, based on a fix hostname and path diff --git a/lib/unstable/Security/Signature/Model/ISignedRequest.php b/lib/unstable/Security/Signature/ISignedRequest.php index 76c033970fe..6f9e143c579 100644 --- a/lib/unstable/Security/Signature/Model/ISignedRequest.php +++ b/lib/unstable/Security/Signature/ISignedRequest.php @@ -6,10 +6,11 @@ declare(strict_types=1); * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -namespace NCU\Security\Signature\Model; +namespace NCU\Security\Signature; use NCU\Security\Signature\Exceptions\SignatoryNotFoundException; use NCU\Security\Signature\Exceptions\SignatureElementNotFoundException; +use NCU\Security\Signature\Model\Signatory; /** * model that store data related to a possible signature. @@ -42,10 +43,10 @@ interface ISignedRequest { * * @param array $elements * - * @return ISignedRequest + * @return self * @since 31.0.0 */ - public function setSignatureElements(array $elements): ISignedRequest; + public function setSigningElements(array $elements): self; /** * get the list of elements in the Signature header of the request @@ -53,7 +54,7 @@ interface ISignedRequest { * @return array * @since 31.0.0 */ - public function getSignatureElements(): array; + public function getSigningElements(): array; /** * @param string $key @@ -62,34 +63,35 @@ interface ISignedRequest { * @throws SignatureElementNotFoundException * @since 31.0.0 */ - public function getSignatureElement(string $key): string; + public function getSigningElement(string $key): string; /** - * store a clear version of the signature + * store data used to generate signature * - * @param string $clearSignature + * @param array $data * - * @return ISignedRequest + * @return self * @since 31.0.0 */ - public function setClearSignature(string $clearSignature): ISignedRequest; + public function setSignatureData(array $data): self; /** - * returns the clear version of the signature + * returns data used to generate signature * - * @return string + * @return array * @since 31.0.0 */ - public function getClearSignature(): string; + public function getSignatureData(): array; /** * set the signed version of the signature * - * @param string $signedSignature - * @return ISignedRequest + * @param string $signature + * + * @return self * @since 31.0.0 */ - public function setSignedSignature(string $signedSignature): ISignedRequest; + public function setSignature(string $signature): self; /** * get the signed version of the signature @@ -97,25 +99,25 @@ interface ISignedRequest { * @return string * @since 31.0.0 */ - public function getSignedSignature(): string; + public function getSignature(): string; /** * set the signatory, containing keys and details, related to this request * - * @param ISignatory $signatory - * @return ISignedRequest + * @param Signatory $signatory + * @return self * @since 31.0.0 */ - public function setSignatory(ISignatory $signatory): ISignedRequest; + public function setSignatory(Signatory $signatory): self; /** * get the signatory, containing keys and details, related to this request * - * @return ISignatory + * @return Signatory * @throws SignatoryNotFoundException * @since 31.0.0 */ - public function getSignatory(): ISignatory; + public function getSignatory(): Signatory; /** * returns if a signatory related to this request have been found and defined diff --git a/lib/unstable/Security/Signature/Model/ISignatory.php b/lib/unstable/Security/Signature/Model/ISignatory.php deleted file mode 100644 index e77b77e66e5..00000000000 --- a/lib/unstable/Security/Signature/Model/ISignatory.php +++ /dev/null @@ -1,160 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors - * SPDX-License-Identifier: AGPL-3.0-or-later - */ -namespace NCU\Security\Signature\Model; - -use NCU\Security\Signature\ISignatoryManager; - -/** - * model that store keys and details related to host and in use protocol - * mandatory details are providerId, host, keyId and public key. - * private key is only used for local signatory, used to sign outgoing request - * - * the pair providerId+host is unique, meaning only one signatory can exist for each host - * and protocol - * - * @since 31.0.0 - * @experimental 31.0.0 - */ -interface ISignatory { - /** - * unique string, related to the ISignatoryManager - * - * @see ISignatoryManager::getProviderId - * @param string $providerId - * - * @return ISignatory - * @since 31.0.0 - */ - public function setProviderId(string $providerId): ISignatory; - - /** - * returns the provider id, unique string related to the ISignatoryManager - * - * @return string - * @since 31.0.0 - */ - public function getProviderId(): string; - - /** - * set account, in case your ISignatoryManager needs to manage multiple keys from same host - * - * @param string $account - * - * @return ISignatory - * @since 31.0.0 - */ - public function setAccount(string $account): ISignatory; - - /** - * return account name, empty string if not set - * - * @return string - * @since 31.0.0 - */ - public function getAccount(): string; - - /** - * returns key id - * - * @return string - * @since 31.0.0 - */ - public function getKeyId(): string; - - /** - * returns public key - * - * @return string - * @since 31.0.0 - */ - public function getPublicKey(): string; - - /** - * returns private key, if available - * - * @return string - * @since 31.0.0 - */ - public function getPrivateKey(): string; - - /** - * set metadata - * - * @param array $metadata - * - * @return ISignatory - * @since 31.0.0 - */ - public function setMetadata(array $metadata): ISignatory; - - /** - * returns metadata - * - * @return array - * @since 31.0.0 - */ - public function getMetadata(): array; - - /** - * update an entry in metadata - * - * @param string $key - * @param string|int $value - * - * @return ISignatory - * @since 31.0.0 - */ - public function setMetaValue(string $key, string|int $value): ISignatory; - - /** - * set SignatoryType - * - * @param SignatoryType $type - * - * @return ISignatory - * @since 31.0.0 - */ - public function setType(SignatoryType $type): ISignatory; - - /** - * returns SignatoryType - * - * @return SignatoryType - * @since 31.0.0 - */ - public function getType(): SignatoryType; - - /** - * set SignatoryStatus - * - * @param SignatoryStatus $status - * - * @see SignatoryStatus - * @return ISignatory - * @since 31.0.0 - */ - public function setStatus(SignatoryStatus $status): ISignatory; - - /** - * get SignatoryStatus - * - * @see SignatoryStatus - * @return SignatoryStatus - * @since 31.0.0 - */ - public function getStatus(): SignatoryStatus; - - /** - * get last timestamp this entry has been updated - * - * @return int - * @since 31.0.0 - */ - public function getLastUpdated(): int; -} diff --git a/lib/unstable/Security/Signature/Model/Signatory.php b/lib/unstable/Security/Signature/Model/Signatory.php new file mode 100644 index 00000000000..621cd5ac7ee --- /dev/null +++ b/lib/unstable/Security/Signature/Model/Signatory.php @@ -0,0 +1,165 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace NCU\Security\Signature\Model; + +use JsonSerializable; +use NCU\Security\Signature\Enum\SignatoryStatus; +use NCU\Security\Signature\Enum\SignatoryType; +use OCP\AppFramework\Db\Entity; + +/** + * model that store keys and details related to host and in use protocol + * mandatory details are providerId, host, keyId and public key. + * private key is only used for local signatory, used to sign outgoing request + * + * the pair providerId+host is unique, meaning only one signatory can exist for each host + * and protocol + * + * @since 31.0.0 + * @experimental 31.0.0 + * + * @method void setProviderId(string $providerId) + * @method string getProviderId() + * @method string getKeyId() + * @method void setPublicKey(string $publicKey) + * @method string getPublicKey() + * @method void setPrivateKey(string $privateKey) + * @method string getPrivateKey() + * @method void setHost(string $host) + * @method string getHost() + * @method void setAccount(string $account) + * @method string getAccount() + * @method void setMetadata(array $metadata) + * @method array getMetadata() + * @method void setCreation(int $creation) + * @method int getCreation() + * @method void setLastUpdated(int $creation) + * @method int getLastUpdated() + */ +class Signatory extends Entity implements JsonSerializable { + protected string $keyId = ''; + protected string $keyIdSum = ''; + protected string $providerId = ''; + protected string $host = ''; + protected string $account = ''; + protected int $type = 9; + protected int $status = 1; + protected array $metadata = []; + protected int $creation = 0; + protected int $lastUpdated = 0; + + /** + * @param string $keyId + * @param string $publicKey + * @param string $privateKey + * @param bool $local + * + * @since 31.0.0 + */ + public function __construct( + string $keyId = '', + protected string $publicKey = '', + protected string $privateKey = '', + private readonly bool $local = false, + ) { + $this->addType('providerId', 'string'); + $this->addType('host', 'string'); + $this->addType('account', 'string'); + $this->addType('keyId', 'string'); + $this->addType('keyIdSum', 'string'); + $this->addType('publicKey', 'string'); + $this->addType('metadata', 'json'); + $this->addType('type', 'integer'); + $this->addType('status', 'integer'); + $this->addType('creation', 'integer'); + $this->addType('lastUpdated', 'integer'); + + $this->setKeyId($keyId); + } + + /** + * @param string $keyId + * + * @since 31.0.0 + */ + public function setKeyId(string $keyId): void { + // if set as local (for current instance), we apply some filters. + if ($this->local) { + // to avoid conflict with duplicate key pairs (ie generated url from the occ command), we enforce https as prefix + if (str_starts_with($keyId, 'http://')) { + $keyId = 'https://' . substr($keyId, 7); + } + + // removing /index.php from generated url + $path = parse_url($keyId, PHP_URL_PATH); + if (str_starts_with($path, '/index.php/')) { + $pos = strpos($keyId, '/index.php'); + if ($pos !== false) { + $keyId = substr_replace($keyId, '', $pos, 10); + } + } + } + $this->keyId = $keyId; + $this->keyIdSum = hash('sha256', $keyId); + } + + /** + * @param SignatoryType $type + * @since 31.0.0 + */ + public function setType(SignatoryType $type): void { + $this->type = $type->value; + } + + /** + * @return SignatoryType + * @since 31.0.0 + */ + public function getType(): SignatoryType { + return SignatoryType::from($this->type); + } + + /** + * @param SignatoryStatus $status + * @since 31.0.0 + */ + public function setStatus(SignatoryStatus $status): void { + $this->status = $status->value; + } + + /** + * @return SignatoryStatus + * @since 31.0.0 + */ + public function getStatus(): SignatoryStatus { + return SignatoryStatus::from($this->status); + } + + /** + * update an entry in metadata + * + * @param string $key + * @param string|int|float|bool|array $value + * @since 31.0.0 + */ + public function setMetaValue(string $key, string|int|float|bool|array $value): void { + $this->metadata[$key] = $value; + } + + /** + * @return array + * @since 31.0.0 + */ + public function jsonSerialize(): array { + return [ + 'keyId' => $this->getKeyId(), + 'publicKeyPem' => $this->getPublicKey() + ]; + } +} |