// if ($rev == '5.12.34') {
// $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
// }
+ if ($rev === '5.36.alpha1') {
+ if (empty(CRM_Utils_Constant::value('CIVICRM_SIGN_KEYS'))) {
+ // NOTE: We don't re-encrypt automatically because the old "civicrm.settings.php" lacks a good key, and we don't keep the old encryption because the format is ambiguous.
+ // The admin may forget to re-enable. That's OK -- this only affects 1 field, this is a secondary defense, and (in the future) we can remind the admin via status-checks.
+ $preUpgradeMessage .= '<p>' . ts('CiviCRM v5.36 introduces a new configuration option to support digital signatures. You may <a href="%1" target="_blank">setup CIVICRM_SIGN_KEYS</a> before or after upgrading. The option is not critical in v5.36, but it may be required for extensions or future upgrades.', [
+ 1 => 'https://docs.civicrm.org/sysadmin/en/latest/upgrade/version-specific/#sign-key',
+ ]) . '</p>';
+ }
+ }
}
/**
}
}
+ if (defined('CIVICRM_SIGN_KEYS') && CIVICRM_SIGN_KEYS !== '') {
+ foreach (explode(' ', CIVICRM_SIGN_KEYS) as $n => $keyExpr) {
+ $key = ['tags' => ['SIGN'], 'weight' => $n];
+ $registry->addSymmetricKey($registry->parseKey($keyExpr) + $key);
+ }
+ }
+
//if (isset($_COOKIE['CIVICRM_FORM_KEY'])) {
// $crypto->addSymmetricKey([
// 'key' => base64_decode($_COOKIE['CIVICRM_FORM_KEY']),
--- /dev/null
+<?php
+/**
+ * @file
+ *
+ * Generate the signing key(s).
+ */
+
+if (!defined('CIVI_SETUP')) {
+ exit("Installation plugins must only be loaded by the installer.\n");
+}
+
+\Civi\Setup::dispatcher()
+ ->addListener('civi.setup.installFiles', function (\Civi\Setup\Event\InstallFilesEvent $e) {
+ \Civi\Setup::log()->info(sprintf('[%s] Handle %s', basename(__FILE__), 'installFiles'));
+
+ $toAlphanum = function($bits) {
+ return preg_replace(';[^a-zA-Z0-9];', '', base64_encode($bits));
+ };
+
+ if (empty($e->getModel()->signKeys)) {
+ $e->getModel()->signKeys = ['jwt-hs256:hkdf-sha256:' . $toAlphanum(random_bytes(40))];
+ // toAlpanum() occasionally loses a few bits of entropy, but random_bytes() has significant excess, so it's still more than ample for 256 bit hkdf.
+ }
+
+ if (is_string($e->getModel()->signKeys)) {
+ $e->getModel()->signKeys = [$e->getModel()->signKeys];
+ }
+
+ \Civi\Setup::log()->info(sprintf('[%s] Done %s', basename(__FILE__), 'installFiles'));
+
+ }, \Civi\Setup::PRIORITY_PREPARE);
$params['CMSdbSSL'] = empty($m->cmsDb['ssl_params']) ? '' : addslashes('&' . http_build_query($m->cmsDb['ssl_params'], '', '&', PHP_QUERY_RFC3986));
$params['siteKey'] = addslashes($m->siteKey);
$params['credKeys'] = addslashes(implode(' ', $m->credKeys));
+ $params['signKeys'] = addslashes(implode(' ', $m->signKeys));
$extraSettings = array();
* Ex: 'abcd1234ABCD9876'.
* @property string[] $credKeys
* Ex: ['::abcd1234ABCD9876'].
+ * @property string[] $signKeys
+ * Ex: ['jwt-hs256::abcd1234ABCD9876'].
* @property string|NULL $lang
* The language of the default dataset.
* Ex: 'fr_FR'.
'name' => 'credKeys',
'type' => 'array',
));
+ $this->addField(array(
+ 'description' => 'Signing keys',
+ 'name' => 'signKeys',
+ 'type' => 'array',
+ ));
$this->addField(array(
'description' => 'Load example data',
'name' => 'loadGenerated',
// Feel free to simplify post-install.
}
+/**
+ * The signing key is used to generate and verify shareable tokens.
+ *
+ * This is a space-delimited list of keys (ordered by priority). Put the preferred
+ * key first. Any old/deprecated keys may be listed after.
+ *
+ * Each key is in format "<cipher-suite>:<key-encoding>:<key-content>", as in:
+ *
+ * Ex: define('CIVICRM_SIGN_KEYS', 'jwt-hs256:hkdf-sha256:RANDOM_1')
+ * Ex: define('CIVICRM_SIGN_KEYS', 'jwt-hs256::RANDOM_2 jwt-hs256::RANDOM_3')
+ * Ex: define('CIVICRM_SIGN_KEYS', 'jwt-hs256:b64:RANDOM_4 jwt-hs256:b64:RANDOM_5')
+ *
+ * If key-encoding is blank, it will default to "hkdf-sha256".
+ */
+if (!defined('CIVICRM_SIGN_KEYS') ) {
+ define( '_CIVICRM_SIGN_KEYS', '%%signKeys%%');
+ define( 'CIVICRM_SIGN_KEYS', _CIVICRM_SIGN_KEYS === '%%' . 'signKeys' . '%%' ? '' : _CIVICRM_SIGN_KEYS );
+ // Some old installers may not set a decent value, and this extra complexity is a failsafe.
+ // Feel free to simplify post-install.
+}
+
/**
* Enable this constant, if you want to send your email through the smarty
* templating engine(allows you to do conditional and more complex logic)