Page MenuHomePhabricator

D11021.id26465.diff
No OneTemporary

D11021.id26465.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1316,6 +1316,7 @@
'PhabricatorAuthLinkController' => 'applications/auth/controller/PhabricatorAuthLinkController.php',
'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php',
'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php',
+ 'PhabricatorAuthManagementCachePKCS8Workflow' => 'applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php',
'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php',
'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php',
'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php',
@@ -4429,6 +4430,7 @@
'PhabricatorAuthLinkController' => 'PhabricatorAuthController',
'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController',
'PhabricatorAuthLoginController' => 'PhabricatorAuthController',
+ 'PhabricatorAuthManagementCachePKCS8Workflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow',
'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow',
diff --git a/src/applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php b/src/applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php
new file mode 100644
--- /dev/null
+++ b/src/applications/auth/management/PhabricatorAuthManagementCachePKCS8Workflow.php
@@ -0,0 +1,96 @@
+<?php
+
+final class PhabricatorAuthManagementCachePKCS8Workflow
+ extends PhabricatorAuthManagementWorkflow {
+
+ protected function didConstruct() {
+ $this
+ ->setName('cache-pkcs8')
+ ->setExamples('**cache-pkcs8** --public __keyfile__ --pkcs8 __keyfile__')
+ ->setSynopsis(
+ pht(
+ 'Cache the PKCS8 format of a public key. When developing on OSX, '.
+ 'this can be used to work around issues with ssh-keygen. Use '.
+ '`ssh-keygen -e -m PKCS8 -f key.pub` to generate a PKCS8 key to '.
+ 'feed to this command.'))
+ ->setArguments(
+ array(
+ array(
+ 'name' => 'public',
+ 'param' => 'keyfile',
+ 'help' => pht('Path to public keyfile.'),
+ ),
+ array(
+ 'name' => 'pkcs8',
+ 'param' => 'keyfile',
+ 'help' => pht('Path to corresponding PKCS8 key.'),
+ ),
+ ));
+ }
+
+ public function execute(PhutilArgumentParser $args) {
+ $console = PhutilConsole::getConsole();
+
+ $public_keyfile = $args->getArg('public');
+ if (!strlen($public_keyfile)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'You must specify the path to a public keyfile with --public.'));
+ }
+
+ if (!Filesystem::pathExists($public_keyfile)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Specified public keyfile "%s" does not exist!',
+ $public_keyfile));
+ }
+
+ $public_key = Filesystem::readFile($public_keyfile);
+
+ $pkcs8_keyfile = $args->getArg('pkcs8');
+ if (!strlen($pkcs8_keyfile)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'You must specify the path to a pkcs8 keyfile with --pkc8s.'));
+ }
+
+ if (!Filesystem::pathExists($pkcs8_keyfile)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Specified pkcs8 keyfile "%s" does not exist!',
+ $pkcs8_keyfile));
+ }
+
+ $pkcs8_key = Filesystem::readFile($pkcs8_keyfile);
+
+ $warning = pht(
+ 'Adding a PKCS8 keyfile to the cache can be very dangerous. If the '.
+ 'PKCS8 file really encodes a different public key than the one '.
+ 'specified, an attacker could use it to gain unautorized access.'.
+ "\n\n".
+ 'Generally, you should use this option only in a development '.
+ 'environment where ssh-keygen is broken and it is inconvenient to '.
+ 'fix it, and only if you are certain you understand the risks. You '.
+ 'should never cache a PKCS8 file you did not generate yourself.');
+
+ $console->writeOut(
+ "%s\n",
+ phutil_console_wrap($warning));
+
+ $prompt = pht('Really trust this PKCS8 keyfile?');
+ if (!phutil_console_confirm($prompt)) {
+ throw new PhutilArgumentUsageException(
+ pht('Aborted workflow.'));
+ }
+
+ $key = PhabricatorAuthSSHPublicKey::newFromRawKey($public_key);
+ $key->forcePopulatePKCS8Cache($pkcs8_key);
+
+ $console->writeOut(
+ "%s\n",
+ pht('Cached PKCS8 key for public key.'));
+
+ return 0;
+ }
+
+}
diff --git a/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php b/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php
--- a/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php
+++ b/src/applications/auth/sshkey/PhabricatorAuthSSHPublicKey.php
@@ -108,17 +108,48 @@
}
public function toPKCS8() {
+ $entire_key = $this->getEntireKey();
+ $cache_key = $this->getPKCS8CacheKey($entire_key);
- // TODO: Put a cache in front of this.
+ $cache = PhabricatorCaches::getImmutableCache();
+ $pkcs8_key = $cache->getKey($cache_key);
+ if ($pkcs8_key) {
+ return $pkcs8_key;
+ }
$tmp = new TempFile();
Filesystem::writeFile($tmp, $this->getEntireKey());
- list($pem_key) = execx(
- 'ssh-keygen -e -m PKCS8 -f %s',
- $tmp);
+ try {
+ list($pkcs8_key) = execx(
+ 'ssh-keygen -e -m PKCS8 -f %s',
+ $tmp);
+ } catch (CommandException $ex) {
+ unset($tmp);
+ throw new PhutilProxyException(
+ pht(
+ 'Failed to convert public key into PKCS8 format. If you are '.
+ 'developing on OSX, you may be able to use `bin/auth cache-pkcs8` '.
+ 'to work around this issue. %s',
+ $ex->getMessage()),
+ $ex);
+ }
unset($tmp);
- return $pem_key;
+ $cache->setKey($cache_key, $pkcs8_key);
+
+ return $pkcs8_key;
+ }
+
+ public function forcePopulatePKCS8Cache($pkcs8_key) {
+ $entire_key = $this->getEntireKey();
+ $cache_key = $this->getPKCS8CacheKey($entire_key);
+
+ $cache = PhabricatorCaches::getImmutableCache();
+ $cache->setKey($cache_key, $pkcs8_key);
+ }
+
+ private function getPKCS8CacheKey($entire_key) {
+ return 'pkcs8:'.PhabricatorHash::digestForIndex($entire_key);
}
}

File Metadata

Mime Type
text/plain
Expires
Sun, Feb 9, 12:23 AM (3 h, 28 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7100758
Default Alt Text
D11021.id26465.diff (6 KB)

Event Timeline