From 8702a8ac4fdf73a69ac839258947a0c953149560 Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Thu, 25 Oct 2018 14:07:46 +1300 Subject: [PATCH] Switch access token signing from RSA SHA-256 to ECDSA SHA-512 --- README.md | 12 ++++++++---- code/Entities/AccessTokenEntity.php | 23 +++++++++++++++++++++++ composer.json | 1 + tests/OauthServerControllerTest.php | 6 +++--- tests/test.crt | 8 ++++---- tests/test.key | 22 +++++++--------------- 6 files changed, 46 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 4fa9ea1..9b33f1b 100644 --- a/README.md +++ b/README.md @@ -23,16 +23,20 @@ Install the add-on with Composer: composer require iansimpson/ss-oauth2-server ``` -Next, generate a private/public key pair: +Next, generate an ECSDA private/public key pair: + +``` +vendor/mdanter/ecc/bin/phpecc genkey --curve nist-p521 --out pem +``` + +Copy the output into `private.key` and `public.key` files respectively. Then fix permissions: ``` -openssl genrsa -out private.key 1024 -openssl rsa -in private.key -pubout -out public.key chmod 600 private.key chmod 600 public.key ``` -And put these on your web server, somewhere outside the web root. Add the following lines in your `mysite/_config/config.yml`, updating the privateKey and publicKey to point to the key file (relative to the Silverstripe root), and adding an encryption key (which you might generate with `php -r 'echo base64_encode(random_bytes(32)), PHP_EOL;'`). +And put these on your web server, somewhere outside the web root. Add the following lines in your `mysite/_config/config.yml`, updating the privateKey and publicKey to point to the key file (relative to the Silverstripe root), and adding an encryption key (which you might generate with `php -r 'echo base64_encode(random_bytes(64)), PHP_EOL;'`). ``` IanSimpson\OauthServerController: diff --git a/code/Entities/AccessTokenEntity.php b/code/Entities/AccessTokenEntity.php index 564b556..0c29436 100644 --- a/code/Entities/AccessTokenEntity.php +++ b/code/Entities/AccessTokenEntity.php @@ -6,6 +6,10 @@ namespace IanSimpson\Entities; +use Lcobucci\JWT\Builder; +use Lcobucci\JWT\Signer\Key; +use Lcobucci\JWT\Signer\Ecdsa\Sha512; +use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Entities\ClientEntityInterface; use League\OAuth2\Server\Entities\ScopeEntityInterface; @@ -43,6 +47,25 @@ class AccessTokenEntity extends \DataObject implements AccessTokenEntityInterfac 'ScopeEntities' => 'IanSimpson\Entities\ScopeEntity', ); + /** + * @param CryptKey $privateKey + * + * @return string + */ + public function convertToJWT(CryptKey $privateKey) + { + return (new Builder()) + ->setAudience($this->getClient()->getIdentifier()) + ->setId($this->getIdentifier(), true) + ->setIssuedAt(time()) + ->setNotBefore(time()) + ->setExpiration($this->getExpiryDateTime()->getTimestamp()) + ->setSubject($this->getUserIdentifier()) + ->set('scopes', $this->getScopes()) + ->sign(new Sha512(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase())) + ->getToken(); + } + public function getIdentifier() { return $this->Code; diff --git a/composer.json b/composer.json index dcb2efa..467c54e 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "silverstripe/cms": "~3.1", "silverstripe/framework": "~3.1", "league/oauth2-server": "^6.1", + "mdanter/ecc": "~0.3.0", "guzzlehttp/psr7": "*" } } diff --git a/tests/OauthServerControllerTest.php b/tests/OauthServerControllerTest.php index 1b3f371..7e06a73 100644 --- a/tests/OauthServerControllerTest.php +++ b/tests/OauthServerControllerTest.php @@ -14,7 +14,7 @@ use Lcobucci\JWT\Builder; use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Key; -use Lcobucci\JWT\Signer\Rsa\Sha256; +use Lcobucci\JWT\Signer\Ecdsa\Sha512; use League\OAuth2\Server\AuthorizationValidators\BearerTokenValidator; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\CryptTrait; @@ -153,7 +153,7 @@ public function testAuthenticateRequest() ->setExpiration(strtotime($at->Expiry)) ->setSubject($m->ID) ->set('scopes', []) - ->sign(new Sha256(), new Key(file_get_contents(__DIR__ . '/test.key'))) + ->sign(new Sha512(), new Key(file_get_contents(__DIR__ . '/test.key'))) ->getToken(); $_SERVER['AUTHORIZATION'] = sprintf('Bearer %s', $jwt); @@ -170,7 +170,7 @@ private function tokenIsOk($jwt) { $pk = new CryptKey(__DIR__ . '/test.crt'); $token = (new Parser())->parse($jwt); - return $token->verify(new Sha256(), $pk->getKeyPath()); + return $token->verify(new Sha512(), $pk->getKeyPath()); } private function tokenGetClaims($jwt) diff --git a/tests/test.crt b/tests/test.crt index 3a64933..2c5ac3f 100644 --- a/tests/test.crt +++ b/tests/test.crt @@ -1,6 +1,6 @@ -----BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCf77SildvvZuEtRyAMWrFpZDTs -+xv0ssQ7xeDxds1Uo6HLQGfwNnNAkqAkjua1uLZSNU6qp1w2zwC368syuWekW474 -u4V5zm+1n2A9ct8yyNydLgQVq0g7j3b+entmqTpZDqUHgNUi1XRyqqUa1AV++1et -Z5bOJjjvyyPmrT+BqwIDAQAB +MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAxkZsteUznOV3Ipwmg4L3lHYYC8Yw +HcKiwjijdutRPHYYsryT+FkzDHPzn0j9Yuxvi6MJfZWCvl/xR3mMi8jrozgBk6lP +ReSN4NNyCUFUsolCVlGb34pHQSf87jGTQ2c5CLJ5bLScJHRSOoOO/CeQ60jOm4Oz +yDWP1WztYA+VVXjlX/M= -----END PUBLIC KEY----- diff --git a/tests/test.key b/tests/test.key index 47712c1..385366a 100644 --- a/tests/test.key +++ b/tests/test.key @@ -1,15 +1,7 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQCf77SildvvZuEtRyAMWrFpZDTs+xv0ssQ7xeDxds1Uo6HLQGfw -NnNAkqAkjua1uLZSNU6qp1w2zwC368syuWekW474u4V5zm+1n2A9ct8yyNydLgQV -q0g7j3b+entmqTpZDqUHgNUi1XRyqqUa1AV++1etZ5bOJjjvyyPmrT+BqwIDAQAB -AoGAOFxppI349nGj0qfo5FGliYVVnVmUbXP98S53acA69aPAZXbp6d3WWaASLS/q -n4lbPrcoZL0bovjpwOaoMdTib5ty/cO2pfo10hby7p0vLZrsPMLLuWvYP2RlqcIZ -vkmzDSZPBGZkd9ieFevdH3/vihD5VuV93leUvP/1ob8ak2kCQQDLA43dOl8crk9R -fvc6gcnj73P2D2+gR7r0kpG90P9xz6w4cA3uitsQnLgvCEMqLwmWrg6BIimJ+feS -eKMfU26VAkEAya3pF69j+f8SQHp4EQnx1Tig+g24PNebxDFtl9Y9GdmlLzFR94zG -Ru7SqLcynMHlgj42PaZtD2dM2yQLpXZfPwJAbNgF+mNuVRE7o4UABhVJ6fQa5wTV -o0hx+uiOTQe9vQZL3qJtRcSauOhdc5HpeLdpW6kMS73GKZykWJpnUsdHlQJAIZrA -xBmNZxKBUA0YBH7LtOOCryeqEzk50y8JO8uO0sfZJkvphH4Ia7lPkJ016bjFLTaA -gzU/5tknjTwsVJ2ssQJAZssVuJ21QK9e2kHgZzNP/oJTcb/t2PsSUO5c5BHwe4UV -yghSCWzz3MWo3rWYEMiBRVmkezPHt0izurNhh8Sg9A== ------END RSA PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEK7lWrkCwd1ZA+pUCOFL80CerhY0iY+vlKenUR75aBH4E6cy6LFV1Zq +SE7zC0fo1yLm73XhIFF+IdpU5awYmXmUOzOgBwYFK4EEACOhgYkDgYYABADGRmy1 +5TOc5XcinCaDgveUdhgLxjAdwqLCOKN261E8dhiyvJP4WTMMc/OfSP1i7G+Lowl9 +lYK+X/FHeYyLyOujOAGTqU9F5I3g03IJQVSyiUJWUZvfikdBJ/zuMZNDZzkIsnls +tJwkdFI6g478J5DrSM6bg7PINY/VbO1gD5VVeOVf8w== +-----END EC PRIVATE KEY-----