Skip to content

Commit

Permalink
Verify user and subkey
Browse files Browse the repository at this point in the history
Signed-off-by: Nguyen Van Nguyen <[email protected]>
  • Loading branch information
nguyennv committed Jan 16, 2024
1 parent c2d69d0 commit a4bd410
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 65 deletions.
150 changes: 87 additions & 63 deletions src/Key/AbstractKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public function getSigningKeyPacket(
);
foreach ($subkeys as $subkey) {
if (empty($keyID) || $keyID === $subkey->getKeyID()) {
if (!$subkey->isSigningKey()) {
if (!$subkey->isSigningKey() || !$subkey->verify($time)) {
continue;
}
$signature = $subkey->getLatestBindingSignature()?->getEmbeddedSignature();
Expand Down Expand Up @@ -307,7 +307,7 @@ public function getEncryptionKeyPacket(
);
foreach ($subkeys as $subkey) {
if (empty($keyID) || $keyID === $subkey->getKeyID()) {
if (!$subkey->isEncryptionKey()) {
if (!$subkey->isEncryptionKey() || !$subkey->verify($time)) {
continue;
}
return $subkey->getKeyPacket();
Expand Down Expand Up @@ -407,7 +407,7 @@ public function isPrivate(): bool
public function aeadSupported(): bool
{
$primaryUser = $this->getPrimaryUser();
$features = $primaryUser->getLatestSelfCertification()?->getFeatures();
$features = $primaryUser?->getLatestSelfCertification()?->getFeatures();
if (($features instanceof Features) && $features->supportAeadEncryptedData()) {
return true;
}
Expand Down Expand Up @@ -463,9 +463,13 @@ public function isCertified(
?DateTimeInterface $time = null
): bool
{
return $this->getPrimaryUser()->isCertified(
$verifyKey, $certificate, $time
);
$primaryUser = $this->getPrimaryUser();
if ($primaryUser instanceof UserInterface) {
return $primaryUser->isCertified(
$verifyKey, $certificate, $time
);
}
return false;
}

/**
Expand Down Expand Up @@ -508,25 +512,11 @@ public function verify(
/**
* {@inheritdoc}
*/
public function getPrimaryUser(?DateTimeInterface $time = null): UserInterface
public function getPrimaryUser(?DateTimeInterface $time = null): ?UserInterface
{
$users = $this->users;
usort(
$users,
static function ($a, $b) {
$aPrimary = (int) $a->isPrimary();
$bPrimary = (int) $b->isPrimary();
if ($aPrimary === $bPrimary) {
$aTime = $a->getLatestSelfCertification()?->getSignatureCreationTime()
?? new \DateTime();
$bTime = $b->getLatestSelfCertification()?->getSignatureCreationTime()
?? new \DateTime();
return $aTime->getTimestamp() - $bTime->getTimestamp();
}
else {
return $aPrimary - $bPrimary;
}
}
$users = array_filter(
$this->getSortedPrimaryUsers(),
static fn ($user) => $user->verify($time)
);
return array_pop($users);
}
Expand All @@ -538,13 +528,17 @@ public function certifyBy(
PrivateKeyInterface $signKey, ?DateTimeInterface $time = null
): self
{
$users = [];
$certifedUserID = '';
$self = $this->clone();
$certifedUser = $self->getPrimaryUser()->certifyBy($signKey, $time);
$users = [
$certifedUser,
];
$primaryUser = $self->getPrimaryUser();
if ($primaryUser instanceof UserInterface) {
$certifedUser = $primaryUser->certifyBy($signKey, $time);
$certifedUserID = $certifedUser->getUserID();
$users[] = $certifedUser;
}
foreach ($self->getUsers() as $user) {
if ($user->getUserID() !== $certifedUser->getUserID()) {
if ($user->getUserID() !== $certifedUserID) {
$users[] = $user;
}
}
Expand Down Expand Up @@ -573,18 +567,58 @@ public function revokeBy(
return $self;
}

/**
* Get key expiration from signatures.
*
* @param array $signatures
* @return DateTimeInterface
*/
public static function getKeyExpiration(array $signatures): ?DateTimeInterface
{
usort(
$signatures,
static function ($a, $b): int {
$aTime = $a->getSignatureCreationTime() ?? new \DateTime();
$bTime = $b->getSignatureCreationTime() ?? new \DateTime();
return $bTime->getTimestamp() - $aTime->getTimestamp();
}
);
foreach ($signatures as $signature) {
$keyExpirationTime = $signature->getKeyExpirationTime();
if ($keyExpirationTime instanceof KeyExpirationTime) {
$expirationTime = $keyExpirationTime->getExpirationTime();
$creationTime = $signature->getSignatureCreationTime() ?? new \DateTime();
$keyExpiry = $creationTime->setTimestamp(
$creationTime->getTimestamp() + $expirationTime
);
$signatureExpiry = $signature->getSignatureExpirationTime();
if (empty($signatureExpiry)) {
return $keyExpiry;
}
else {
return $keyExpiry < $signatureExpiry ? $keyExpiry : $signatureExpiry;
}
}
else {
return $signature->getSignatureExpirationTime();
}
}
return null;
}

/**
* Return the key is signing or verification key
*
* @return bool
*/
protected function isSigningKey(?DateTimeInterface $time = null): bool
protected function isSigningKey(): bool
{
if (!$this->keyPacket->isSigningKey()) {
return false;
}
$primaryUser = $this->getPrimaryUser($time);
$keyFlags = $primaryUser->getLatestSelfCertification()?->getKeyFlags();
$users = $this->getSortedPrimaryUsers();
$user = array_pop($users);
$keyFlags = $user?->getLatestSelfCertification()?->getKeyFlags();
if (($keyFlags instanceof KeyFlags) && !$keyFlags->isSignData()) {
return false;
}
Expand All @@ -596,13 +630,14 @@ protected function isSigningKey(?DateTimeInterface $time = null): bool
*
* @return bool
*/
protected function isEncryptionKey(?DateTimeInterface $time = null): bool
protected function isEncryptionKey(): bool
{
if (!$this->keyPacket->isEncryptionKey()) {
return false;
}
$primaryUser = $this->getPrimaryUser($time);
$keyFlags = $primaryUser->getLatestSelfCertification()?->getKeyFlags();
$users = $this->getSortedPrimaryUsers();
$user = array_pop($users);
$keyFlags = $user?->getLatestSelfCertification()?->getKeyFlags();
if (($keyFlags instanceof KeyFlags) &&
!($keyFlags->isEncryptCommunication() || $keyFlags->isEncryptStorage()))
{
Expand All @@ -612,42 +647,31 @@ protected function isEncryptionKey(?DateTimeInterface $time = null): bool
}

/**
* Get key expiration from signatures.
* Get sorted primary users.
*
* @param array $signatures
* @return DateTimeInterface
* @return array
*/
public static function getKeyExpiration(array $signatures): ?DateTimeInterface
protected function getSortedPrimaryUsers(): array
{
$users = $this->users;
usort(
$signatures,
static function ($a, $b): int {
$aTime = $a->getSignatureCreationTime() ?? new \DateTime();
$bTime = $b->getSignatureCreationTime() ?? new \DateTime();
return $bTime->getTimestamp() - $aTime->getTimestamp();
}
);
foreach ($signatures as $signature) {
$keyExpirationTime = $signature->getKeyExpirationTime();
if ($keyExpirationTime instanceof KeyExpirationTime) {
$expirationTime = $keyExpirationTime->getExpirationTime();
$creationTime = $signature->getSignatureCreationTime() ?? new \DateTime();
$keyExpiry = $creationTime->setTimestamp(
$creationTime->getTimestamp() + $expirationTime
);
$signatureExpiry = $signature->getSignatureExpirationTime();
if (empty($signatureExpiry)) {
return $keyExpiry;
$users,
static function ($a, $b) {
$aPrimary = (int) $a->isPrimary();
$bPrimary = (int) $b->isPrimary();
if ($aPrimary === $bPrimary) {
$aTime = $a->getLatestSelfCertification()?->getSignatureCreationTime()
?? new \DateTime();
$bTime = $b->getLatestSelfCertification()?->getSignatureCreationTime()
?? new \DateTime();
return $aTime->getTimestamp() - $bTime->getTimestamp();
}
else {
return $keyExpiry < $signatureExpiry ? $keyExpiry : $signatureExpiry;
return $aPrimary - $bPrimary;
}
}
else {
return $signature->getSignatureExpirationTime();
}
}
return null;
);
return $users;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Key/PrivateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ public function getDecryptionKeyPackets(
$keyPackets = [];
foreach ($subkeys as $subkey) {
if (empty($keyID) || $keyID === $subkey->getKeyID()) {
if (!$subkey->isEncryptionKey()) {
if (!$subkey->isEncryptionKey() || !$subkey->verify($time)) {
continue;
}
$keyPackets[] = $subkey->getKeyPacket();
Expand Down
2 changes: 1 addition & 1 deletion src/Type/KeyInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function getEncryptionKeyPacket(
* @param DateTimeInterface $time
* @return UserInterface
*/
function getPrimaryUser(?DateTimeInterface $time = null): UserInterface;
function getPrimaryUser(?DateTimeInterface $time = null): ?UserInterface;

/**
* Return key is private
Expand Down

0 comments on commit a4bd410

Please sign in to comment.