diff --git a/bin/jose b/bin/jose index c0c06ba9..d3f2b86e 100644 --- a/bin/jose +++ b/bin/jose @@ -68,6 +68,7 @@ $application->add(new Console\RsaKeysetGeneratorCommand($jsonConverter)); $application->add(new Console\MergeKeysetCommand($jsonConverter)); $application->add(new Console\PublicKeysetCommand($jsonConverter)); $application->add(new Console\RotateKeysetCommand($jsonConverter)); +$application->add(new Console\AddKeyIntoKeysetCommand($jsonConverter)); $application->add(new Console\OptimizeRsaKeyCommand($jsonConverter)); $application->add(new Console\KeyAnalyzerCommand($jwkAnalyzerManager, $jsonConverter)); diff --git a/src/Bundle/Console/Resources/config/commands.yml b/src/Bundle/Console/Resources/config/commands.yml index 059b8a47..4a14f1e5 100644 --- a/src/Bundle/Console/Resources/config/commands.yml +++ b/src/Bundle/Console/Resources/config/commands.yml @@ -76,6 +76,14 @@ services: tags: - {name: 'console.command'} + Jose\Component\Console\RotateKeysetCommand: + tags: + - {name: 'console.command'} + + Jose\Component\Console\AddKeyIntoKeysetCommand: + tags: + - {name: 'console.command'} + Jose\Component\Console\PemConverterCommand: tags: - {name: 'console.command'} diff --git a/src/Component/Console/AbstractGeneratorCommand.php b/src/Component/Console/AbstractGeneratorCommand.php index f988ca29..cbb7c4e2 100644 --- a/src/Component/Console/AbstractGeneratorCommand.php +++ b/src/Component/Console/AbstractGeneratorCommand.php @@ -13,6 +13,7 @@ namespace Jose\Component\Console; +use Base64Url\Base64Url; use Jose\Component\KeyManagement\JWKFactory; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -39,6 +40,7 @@ protected function configure() $this ->addOption('use', 'u', InputOption::VALUE_OPTIONAL, 'Usage of the key. Must be either "sig" or "enc".') ->addOption('alg', 'a', InputOption::VALUE_OPTIONAL, 'Algorithm for the key.') + ->addOption('random_id', null, InputOption::VALUE_NONE, 'If this option is set, a random key ID (kid) will be generated.') ; } @@ -50,6 +52,9 @@ protected function configure() protected function getOptions(InputInterface $input): array { $args = []; + if ($input->getOption('random_id')) { + $args['kid'] = $this->generateKeyID(); + } foreach (['use', 'alg'] as $key) { $value = $input->getOption($key); if (null !== $value) { @@ -59,4 +64,12 @@ protected function getOptions(InputInterface $input): array return $args; } + + /** + * @return string + */ + private function generateKeyID(): string + { + return Base64Url::encode(random_bytes(64)); + } } diff --git a/src/Component/Console/AddKeyIntoKeysetCommand.php b/src/Component/Console/AddKeyIntoKeysetCommand.php new file mode 100644 index 00000000..0c8fecab --- /dev/null +++ b/src/Component/Console/AddKeyIntoKeysetCommand.php @@ -0,0 +1,96 @@ +setName('keyset:add:key') + ->setDescription('Add a key into a key set.') + ->setHelp('This command adds a key at the end of a key set.') + ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object') + ->addArgument('jwk', InputArgument::REQUIRED, 'The new JWK object') + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $jwkset = $this->getKeyset($input); + $jwk = $this->getKey($input); + $jwkset = $jwkset->with($jwk); + $this->prepareJsonOutput($input, $output,$jwkset); + } + + /** + * @param InputInterface $input + * + * @return JWKSet + */ + private function getKeyset(InputInterface $input): JWKSet + { + $jwkset = $input->getArgument('jwkset'); + $json = $this->jsonConverter->decode($jwkset); + if (is_array($json)) { + return JWKSet::createFromKeyData($json); + } + + throw new \InvalidArgumentException('The argument must be a valid JWKSet.'); + } + + /** + * @param InputInterface $input + * + * @return JWK + */ + private function getKey(InputInterface $input): JWK + { + $jwkset = $input->getArgument('jwk'); + $json = $this->jsonConverter->decode($jwkset); + if (is_array($json)) { + return JWK::create($json); + } + + throw new \InvalidArgumentException('The argument must be a valid JWK.'); + } +} diff --git a/src/Component/Console/EcKeysetGeneratorCommand.php b/src/Component/Console/EcKeysetGeneratorCommand.php index 73b72d97..67e79b35 100644 --- a/src/Component/Console/EcKeysetGeneratorCommand.php +++ b/src/Component/Console/EcKeysetGeneratorCommand.php @@ -44,10 +44,10 @@ protected function execute(InputInterface $input, OutputInterface $output) { $quantity = (int) $input->getArgument('quantity'); $curve = $input->getArgument('curve'); - $args = $this->getOptions($input); $keyset = JWKSet::createFromKeys([]); for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); $keyset = $keyset->with(JWKFactory::createECKey($curve, $args)); } $this->prepareJsonOutput($input, $output, $keyset); diff --git a/src/Component/Console/MergeKeysetCommand.php b/src/Component/Console/MergeKeysetCommand.php index 0bb1c928..15e3445c 100644 --- a/src/Component/Console/MergeKeysetCommand.php +++ b/src/Component/Console/MergeKeysetCommand.php @@ -22,7 +22,7 @@ /** * Class MergeKeysetCommand. */ -final class MergeKeysetCommand extends AbstractGeneratorCommand +final class MergeKeysetCommand extends AbstractObjectOutputCommand { /** * KeyAnalyzerCommand constructor. @@ -42,7 +42,7 @@ protected function configure() { parent::configure(); $this - ->setName('keyset:convert:merge') + ->setName('keyset:merge') ->setDescription('Merge several key sets into one.') ->setHelp('This command merges several key sets into one. It is very useful when you generate e.g. RSA, EC and OKP keys and you want only one key set to rule them all.') ->addArgument('jwksets', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'The JWKSet objects') diff --git a/src/Component/Console/OctKeysetGeneratorCommand.php b/src/Component/Console/OctKeysetGeneratorCommand.php index 9425d695..4e8aad84 100644 --- a/src/Component/Console/OctKeysetGeneratorCommand.php +++ b/src/Component/Console/OctKeysetGeneratorCommand.php @@ -44,10 +44,10 @@ protected function execute(InputInterface $input, OutputInterface $output) { $quantity = (int) $input->getArgument('quantity'); $size = (int) $input->getArgument('size'); - $args = $this->getOptions($input); $keyset = JWKSet::createFromKeys([]); for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); $keyset = $keyset->with(JWKFactory::createOctKey($size, $args)); } $this->prepareJsonOutput($input, $output, $keyset); diff --git a/src/Component/Console/OkpKeysetGeneratorCommand.php b/src/Component/Console/OkpKeysetGeneratorCommand.php index 44a66673..2bb9fa93 100644 --- a/src/Component/Console/OkpKeysetGeneratorCommand.php +++ b/src/Component/Console/OkpKeysetGeneratorCommand.php @@ -44,10 +44,10 @@ protected function execute(InputInterface $input, OutputInterface $output) { $quantity = (int) $input->getArgument('quantity'); $curve = $input->getArgument('curve'); - $args = $this->getOptions($input); $keyset = JWKSet::createFromKeys([]); for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); $keyset = $keyset->with(JWKFactory::createOKPKey($curve, $args)); } $this->prepareJsonOutput($input, $output, $keyset); diff --git a/src/Component/Console/PublicKeysetCommand.php b/src/Component/Console/PublicKeysetCommand.php index f86bd5af..65363d9e 100644 --- a/src/Component/Console/PublicKeysetCommand.php +++ b/src/Component/Console/PublicKeysetCommand.php @@ -22,7 +22,7 @@ /** * Class PublicKeysetCommand. */ -final class PublicKeysetCommand extends AbstractGeneratorCommand +final class PublicKeysetCommand extends AbstractObjectOutputCommand { /** * KeyAnalyzerCommand constructor. diff --git a/src/Component/Console/RotateKeysetCommand.php b/src/Component/Console/RotateKeysetCommand.php index 9cac0a86..f3c572fa 100644 --- a/src/Component/Console/RotateKeysetCommand.php +++ b/src/Component/Console/RotateKeysetCommand.php @@ -23,7 +23,7 @@ /** * Class RotateKeysetCommand. */ -final class RotateKeysetCommand extends AbstractGeneratorCommand +final class RotateKeysetCommand extends AbstractObjectOutputCommand { /** * KeyAnalyzerCommand constructor. @@ -43,7 +43,7 @@ protected function configure() { parent::configure(); $this - ->setName('keyset:convert:rotate') + ->setName('keyset:rotate') ->setDescription('Rotate a key set.') ->setHelp('This command removes the last key in a key set a place a new one at the beginning.') ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object') diff --git a/src/Component/Console/RsaKeysetGeneratorCommand.php b/src/Component/Console/RsaKeysetGeneratorCommand.php index c03815a0..04eb1854 100644 --- a/src/Component/Console/RsaKeysetGeneratorCommand.php +++ b/src/Component/Console/RsaKeysetGeneratorCommand.php @@ -44,10 +44,10 @@ protected function execute(InputInterface $input, OutputInterface $output) { $quantity = (int) $input->getArgument('quantity'); $size = (int) $input->getArgument('size'); - $args = $this->getOptions($input); $keyset = JWKSet::createFromKeys([]); for ($i = 0; $i < $quantity; ++$i) { + $args = $this->getOptions($input); $keyset = $keyset->with(JWKFactory::createRSAKey($size, $args)); } $this->prepareJsonOutput($input, $output, $keyset);