Skip to content

Commit

Permalink
Merge 10dbe79 into b2526df
Browse files Browse the repository at this point in the history
  • Loading branch information
SergeySidorov committed Jun 2, 2020
2 parents b2526df + 10dbe79 commit 3509af1
Show file tree
Hide file tree
Showing 14 changed files with 551 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ install:
- (cd tests/AuthenticationBot && npm install --no-progress)

before_script:
- export ESIA_CLIENT_OPENSSL_TOOL_PATH="docker run --rm -i -v $(pwd):$(pwd) -w $(pwd) rnix/openssl-gost openssl"
- export ESIA_CLIENT_OPENSSL_TOOL_PATH="docker run --rm -i -v /tmp:/tmp -v $(pwd):$(pwd) -w $(pwd) rnix/openssl-gost openssl"
- export ESIA_LOGIN_ATTEMPTS=3

script:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": "^5.6 || ^7.0",
"lcobucci/jwt": "^3.2.2",
"lcobucci/jwt": "^3.3.2",
"league/oauth2-client": "^2.4.1",
"psr/log": "^1.0",
"ramsey/uuid": "^3.0"
Expand Down
34 changes: 21 additions & 13 deletions composer.lock.dist

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions resources/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,13 @@ View

openssl asn1parse -i -in ekapusta.gost.test.cer
openssl asn1parse -i -in ekapusta.rsa.test.cer

Download GOST ESIA certs
----

```
wget http://esia.gosuslugi.ru/public/esia.zip
...
openssl x509 -inform der -in ГОСТ12_ТЕСИА.cer -out esia.gost.test.cer
openssl x509 -inform der -in "ГОСТ 2012 ПРОД.cer" -out esia.gost.prod.cer
```
12 changes: 12 additions & 0 deletions resources/ekapusta.gost2012.test.cer
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBtTCCAWCgAwIBAgIUTnW9KJWjOLkFOeTy8KU/bRKls7kwDAYIKoUDBwEBAwIF
ADArMQswCQYDVQQGEwJSVTEcMBoGA1UEAwwTVGVzdGVyIEdPU1QyMDEyXzI1NjAe
Fw0yMDA1MjIwNjUzNTZaFw0yMTA1MjIwNjUzNTZaMCsxCzAJBgNVBAYTAlJVMRww
GgYDVQQDDBNUZXN0ZXIgR09TVDIwMTJfMjU2MGYwHwYIKoUDBwEBAQEwEwYHKoUD
AgIjAQYIKoUDBwEBAgIDQwAEQFP71UGhJujcwnawQRlgeRqNfGlgZMqKBuRtY2U5
Rdtha89ZEWWKy7opz13Lawq5X17D2c6sWxjm0rjXc/lJvpajUzBRMB0GA1UdDgQW
BBSeAYo/Enmk1U/xGDVzPH7j3X/GKzAfBgNVHSMEGDAWgBSeAYo/Enmk1U/xGDVz
PH7j3X/GKzAPBgNVHRMBAf8EBTADAQH/MAwGCCqFAwcBAQMCBQADQQAUtp+iBIOf
6joBCPqbn8D+oTJdMpq3xNytyHV1mdC4FEb/be50Z2UsvDlmAhakLqp03afunCEm
KFJZVkbGZz/S
-----END CERTIFICATE-----
4 changes: 4 additions & 0 deletions resources/ekapusta.gost2012.test.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PRIVATE KEY-----
MEYCAQAwHwYIKoUDBwEBAQEwEwYHKoUDAgIjAQYIKoUDBwEBAgIEIOcMlHT4xjrd
ZyIpl1iL2OPZP/JTZFkntS3qUosYS+3O
-----END PRIVATE KEY-----
51 changes: 51 additions & 0 deletions resources/esia.gost.prod.cer
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
-----BEGIN CERTIFICATE-----
MIIJFDCCCMGgAwIBAgIQITfIAHSrm6ZJvmo7SoMwDDAKBggqhQMHAQEDAjCCAWQx
FzAVBgkqhkiG9w0BCQEWCGNhQHJ0LnJ1MRgwFgYFKoUDZAESDTEwMjc3MDAxOTg3
NjcxGjAYBggqhQMDgQMBARIMMDA3NzA3MDQ5Mzg4MQswCQYDVQQGEwJSVTEpMCcG
A1UECAwgNzgg0KHQsNC90LrRgi3Qn9C10YLQtdGA0LHRg9GA0LMxKjAoBgNVBAcM
IdCzLiDQodCw0L3QutGCLdCf0LXRgtC10YDQsdGD0YDQszEtMCsGA1UECQwk0YPQ
uy4g0JTQvtGB0YLQvtC10LLRgdC60L7Qs9C+INC0LjE1MTAwLgYDVQQLDCfQo9C0
0L7RgdGC0L7QstC10YDRj9GO0YnQuNC5INGG0LXQvdGC0YAxJjAkBgNVBAoMHdCf
0JDQniAi0KDQvtGB0YLQtdC70LXQutC+0LwiMSYwJAYDVQQDDB3Qn9CQ0J4gItCg
0L7RgdGC0LXQu9C10LrQvtC8IjAeFw0yMDAzMDQxMTU4NThaFw0yMTAzMDQxMjA4
NThaMIICPTEgMB4GCSqGSIb3DQEJARYRc2RAc2MubWluc3Z5YXoucnUxGjAYBggq
hQMDgQMBARIMMDA3NzEwNDc0Mzc1MRgwFgYFKoUDZAESDTEwNDc3MDIwMjY3MDEx
gagwgaUGA1UECgyBndCc0LjQvdC40YHRgtC10YDRgdGC0LLQviDRhtC40YTRgNC+
0LLQvtCz0L4g0YDQsNC30LLQuNGC0LjRjywg0YHQstGP0LfQuCDQuCDQvNCw0YHR
gdC+0LLRi9GFINC60L7QvNC80YPQvdC40LrQsNGG0LjQuSDQoNC+0YHRgdC40LnR
gdC60L7QuSDQpNC10LTQtdGA0LDRhtC40LgxSzBJBgNVBAkMQtCf0YDQtdGB0L3Q
tdC90YHQutCw0Y8g0L3QsNCxLiwg0LQuMTAsINGB0YLRgC4yLCBJUS3QutCy0LDR
gNGC0LDQuzEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMRwwGgYDVQQIDBM3NyDQsy4g
0JzQvtGB0LrQstCwMQswCQYDVQQGEwJSVTGBqDCBpQYDVQQDDIGd0JzQuNC90LjR
gdGC0LXRgNGB0YLQstC+INGG0LjRhNGA0L7QstC+0LPQviDRgNCw0LfQstC40YLQ
uNGPLCDRgdCy0Y/Qt9C4INC4INC80LDRgdGB0L7QstGL0YUg0LrQvtC80LzRg9C9
0LjQutCw0YbQuNC5INCg0L7RgdGB0LjQudGB0LrQvtC5INCk0LXQtNC10YDQsNGG
0LjQuDBmMB8GCCqFAwcBAQEBMBMGByqFAwICJAAGCCqFAwcBAQICA0MABEAfH7eT
bq4WuD43FqOsZt2Ux3yo19JTIM/vG2FqmP5ylRCVUQ6wLyrOWnMmuTbK4bpMlnZB
d6eM+6TqVHoRMkdoo4IEaTCCBGUwDgYDVR0PAQH/BAQDAgTwMB0GA1UdDgQWBBQS
Y+yaRa3N3i8RpsfsCiFu/IkunzAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
AwQwgYQGCCsGAQUFBwEBBHgwdjA6BggrBgEFBQcwAoYuaHR0cDovL2NlcnRlbnJv
bGwuY2EucnQucnUvY2FfcnRrX2dvc3QyMDEyLmNydDA4BggrBgEFBQcwAoYsaHR0
cDovL2NvbXBhbnkucnQucnUvY2RwL2NhX3J0a19nb3N0MjAxMi5jcnQwHQYDVR0g
BBYwFDAIBgYqhQNkcQEwCAYGKoUDZHECMIIBMAYFKoUDZHAEggElMIIBIQwrItCa
0YDQuNC/0YLQvtCf0YDQviBDU1AiICjQstC10YDRgdC40Y8gNC4wKQwsItCa0YDQ
uNC/0YLQvtCf0YDQviDQo9CmIiAo0LLQtdGA0YHQuNC4IDIuMCkMYdCh0LXRgNGC
0LjRhNC40LrQsNGC0Ysg0YHQvtC+0YLQstC10YLRgdGC0LLQuNGPINCk0KHQkSDQ
oNC+0YHRgdC40Lgg0KHQpC8xMjQtMzYxMiDQvtGCIDEwLjAxLjIwMTkMYdCh0LXR
gNGC0LjRhNC40LrQsNGC0Ysg0YHQvtC+0YLQstC10YLRgdGC0LLQuNGPINCk0KHQ
kSDQoNC+0YHRgdC40Lgg0KHQpC8xMjgtMzU5MiDQvtGCIDE3LjEwLjIwMTgwNgYF
KoUDZG8ELQwrItCa0YDQuNC/0YLQvtCf0YDQviBDU1AiICjQstC10YDRgdC40Y8g
NC4wKTBzBgNVHR8EbDBqMDSgMqAwhi5odHRwOi8vY2VydGVucm9sbC5jYS5ydC5y
dS9jYV9ydGtfZ29zdDIwMTIuY3JsMDKgMKAuhixodHRwOi8vY29tcGFueS5ydC5y
dS9jZHAvY2FfcnRrX2dvc3QyMDEyLmNybDCCAV8GA1UdIwSCAVYwggFSgBT+n7Qo
o99+6jhy++CYZr6rQR7krKGCASykggEoMIIBJDEeMBwGCSqGSIb3DQEJARYPZGl0
QG1pbnN2eWF6LnJ1MQswCQYDVQQGEwJSVTEYMBYGA1UECAwPNzcg0JzQvtGB0LrQ
stCwMRkwFwYDVQQHDBDQsy4g0JzQvtGB0LrQstCwMS4wLAYDVQQJDCXRg9C70LjR
htCwINCi0LLQtdGA0YHQutCw0Y8sINC00L7QvCA3MSwwKgYDVQQKDCPQnNC40L3Q
utC+0LzRgdCy0Y/Qt9GMINCg0L7RgdGB0LjQuDEYMBYGBSqFA2QBEg0xMDQ3NzAy
MDI2NzAxMRowGAYIKoUDA4EDAQESDDAwNzcxMDQ3NDM3NTEsMCoGA1UEAwwj0JzQ
uNC90LrQvtC80YHQstGP0LfRjCDQoNC+0YHRgdC40LiCCk73WTcAAAAAAKQwKwYD
VR0QBCQwIoAPMjAyMDAzMDQxMTU4NThagQ8yMDIxMDMwNDExNTg1OFowCgYIKoUD
BwEBAwIDQQAJ8YpQwom+ZZBq9ist3cjgFYmEqKTAaWVRmkSw7ITLif5sB3y59i43
rco6KTfxuUONoBdD/VZR9PDlTFG3ngM9
-----END CERTIFICATE-----
44 changes: 44 additions & 0 deletions resources/esia.gost.test.cer
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
-----BEGIN CERTIFICATE-----
MIIHtjCCB2OgAwIBAgIQcgsBVlAAw5npET6pGXZzJjAKBggqhQMHAQEDAjCCAT8x
GDAWBgUqhQNkARINMTAyNzcwMDE5ODc2NzEaMBgGCCqFAwOBAwEBEgwwMDc3MDcw
NDkzODgxCzAJBgNVBAYTAlJVMSkwJwYDVQQIDCA3OCDQodCw0L3QutGCLdCf0LXR
gtC10YDQsdGD0YDQszEmMCQGA1UEBwwd0KHQsNC90LrRgi3Qn9C10YLQtdGA0LHR
g9GA0LMxWDBWBgNVBAkMTzE5MTAwMiwg0LMuINCh0LDQvdC60YIt0J/QtdGC0LXR
gNCx0YPRgNCzLCDRg9C7LiDQlNC+0YHRgtC+0LXQstGB0LrQvtCz0L4g0LQuMTUx
JjAkBgNVBAoMHdCf0JDQniAi0KDQvtGB0YLQtdC70LXQutC+0LwiMSUwIwYDVQQD
DBzQotC10YHRgtC+0LLRi9C5INCj0KYg0KDQotCaMB4XDTE5MDcxODA5MTY0MloX
DTIwMDcxODA5MjY0MlowggFRMRowGAYIKoUDA4EDAQESDDAwNzcxMDQ3NDM3NTEY
MBYGBSqFA2QBEg0xMDQ3NzAyMDI2NzAxMSwwKgYDVQQKDCPQnNC40L3QutC+0LzR
gdCy0Y/Qt9GMINCg0L7RgdGB0LjQuDElMCMGA1UECQwc0YPQuy4g0KLQstC10YDR
gdC60LDRjywg0LQuNzEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMRwwGgYDVQQIDBM3
NyDQsy4g0JzQvtGB0LrQstCwMQswCQYDVQQGEwJSVTGBgTB/BgNVBAMMeNCc0LjQ
vdC40YHRgtC10YDRgdGC0LLQviDRgdCy0Y/Qt9C4INC4INC80LDRgdGB0L7QstGL
0YUg0LrQvtC80LzRg9C90LjQutCw0YbQuNC5INCg0L7RgdGB0LjQudGB0LrQvtC5
INCk0LXQtNC10YDQsNGG0LjQuDBmMB8GCCqFAwcBAQEBMBMGByqFAwICJAAGCCqF
AwcBAQICA0MABEAkfzprgr65/W4wVncdHfW1yJpc5LWwHaP+tiTxHsbG1Zm7m8wO
NODfZVlGJGSzqUukmdEFDbrXRYBMCkGRmBgao4IEHDCCBBgwDgYDVR0PAQH/BAQD
AgTwMB0GA1UdDgQWBBRAz3CCZt4D/QqiiC9FZQmnDjqc/TCCAYAGA1UdIwSCAXcw
ggFzgBRIEK8PXdyZJHb3vw3aS30N2Uzh96GCAUekggFDMIIBPzEYMBYGBSqFA2QB
Eg0xMDI3NzAwMTk4NzY3MRowGAYIKoUDA4EDAQESDDAwNzcwNzA0OTM4ODELMAkG
A1UEBhMCUlUxKTAnBgNVBAgMIDc4INCh0LDQvdC60YIt0J/QtdGC0LXRgNCx0YPR
gNCzMSYwJAYDVQQHDB3QodCw0L3QutGCLdCf0LXRgtC10YDQsdGD0YDQszFYMFYG
A1UECQxPMTkxMDAyLCDQsy4g0KHQsNC90LrRgi3Qn9C10YLQtdGA0LHRg9GA0LMs
INGD0LsuINCU0L7RgdGC0L7QtdCy0YHQutC+0LPQviDQtC4xNTEmMCQGA1UECgwd
0J/QkNCeICLQoNC+0YHRgtC10LvQtdC60L7QvCIxJTAjBgNVBAMMHNCi0LXRgdGC
0L7QstGL0Lkg0KPQpiDQoNCi0JqCEHILAVZQABCz6BGkaEvrr/swHQYDVR0lBBYw
FAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdIAQWMBQwCAYGKoUDZHEBMAgGBiqF
A2RxAjArBgNVHRAEJDAigA8yMDE5MDcxODA5MTY0MlqBDzIwMjAwNzE4MDkxNjQy
WjCCARAGBSqFA2RwBIIBBTCCAQEMGtCa0YDQuNC/0YLQvtCf0YDQviBDU1AgNC4w
DB3QmtGA0LjQv9GC0L7Qn9GA0L4g0KPQpiB2LjIuMAxh0KHQtdGA0YLQuNGE0LjQ
utCw0YLRiyDRgdC+0L7RgtCy0LXRgtGB0YLQstC40Y8g0KTQodCRINCg0L7RgdGB
0LjQuCDQodCkLzEyNC0zMzgwINC+0YIgMTEuMDUuMjAxOAxh0KHQtdGA0YLQuNGE
0LjQutCw0YLRiyDRgdC+0L7RgtCy0LXRgtGB0YLQstC40Y8g0KTQodCRINCg0L7R
gdGB0LjQuCDQodCkLzEyOC0yOTgzINC+0YIgMTguMTEuMjAxNjAlBgUqhQNkbwQc
DBrQmtGA0LjQv9GC0L7Qn9GA0L4gQ1NQIDQuMDBlBgNVHR8EXjBcMFqgWKBWhlRo
dHRwOi8vY2VydGVucm9sbC50ZXN0Lmdvc3VzbHVnaS5ydS9jZHAvNDgxMGFmMGY1
ZGRjOTkyNDc2ZjdiZjBkZGE0YjdkMGRkOTRjZTFmNy5jcmwwVgYIKwYBBQUHAQEE
SjBIMEYGCCsGAQUFBzAChjpodHRwOi8vY2VydGVucm9sbC50ZXN0Lmdvc3VzbHVn
aS5ydS9yYS9jZHAvdGVzdF9jYV9ydGsuY2VyMAoGCCqFAwcBAQMCA0EA+xXnnMyk
++qMOJmY5D2l8jkxTRxhlm7WAEJvd8IllZc3J+4eOucK3Oy4XGdH+A8Lcuva2qoT
WmZUtyrxkj9g0w==
-----END CERTIFICATE-----
12 changes: 11 additions & 1 deletion src/Provider/EsiaProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Ekapusta\OAuth2Esia\Token\EsiaAccessToken;
use InvalidArgumentException;
use Lcobucci\JWT\Parsing\Encoder;
use Lcobucci\JWT\Signer as RemoteSignerInterface;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Provider\AbstractProvider;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
Expand All @@ -34,6 +35,11 @@ class EsiaProvider extends AbstractProvider implements ProviderInterface
*/
private $signer;

/**
* @var RemoteSignerInterface
*/
private $remoteSigner;

/**
* @var Encoder
*/
Expand All @@ -55,6 +61,10 @@ public function __construct(array $options = [], array $collaborators = [])
} else {
throw new InvalidArgumentException('Signer is not provided!');
}

if (isset($collaborators['remoteSigner']) && $collaborators['remoteSigner'] instanceof RemoteSignerInterface) {
$this->remoteSigner = $collaborators['remoteSigner'];
}
}

public function getBaseAuthorizationUrl()
Expand Down Expand Up @@ -195,7 +205,7 @@ protected function checkResponse(ResponseInterface $response, $data)

protected function createAccessToken(array $response, AbstractGrant $grant)
{
return new EsiaAccessToken($response, $this->remoteCertificatePath);
return new EsiaAccessToken($response, $this->remoteCertificatePath, $this->remoteSigner);
}

protected function createResourceOwner(array $response, AccessToken $token)
Expand Down
72 changes: 72 additions & 0 deletions src/Security/RemoteSigner/OpensslCli.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Ekapusta\OAuth2Esia\Security\RemoteSigner;

use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\OpenSSL;

class OpensslCli extends OpenSSL
{
private $toolPath;

public function __construct($toolPath = 'openssl')
{
$this->toolPath = $toolPath;
}

public function getKeyType()
{
throw new \RuntimeException('not implemented');
}

public function getAlgorithm()
{
throw new \RuntimeException('not implemented');
}

public function getAlgorithmId()
{
return 'GOST3410_2012_256';
}

public function doVerify($expected, $payload, Key $key)
{
$certificateFile = tempnam(sys_get_temp_dir(), 'certificateFile');
$publicKeyFile = tempnam(sys_get_temp_dir(), 'publicKeyFile');
$messageFile = tempnam(sys_get_temp_dir(), 'messageFile');
$signatureFile = tempnam(sys_get_temp_dir(), 'signatureFile');
file_put_contents($certificateFile, $key->getContent());
file_put_contents($messageFile, $payload);
file_put_contents($signatureFile, $expected);

$code = $this->runParameters([
'x509 -pubkey -noout',
'-in '.escapeshellarg($certificateFile),
'-out '.escapeshellarg($publicKeyFile)
]);
if (0 != $code) {
throw new \RuntimeException('Can\'t extract public key');
}

$code = $this->runParameters([
'dgst -engine gost -md_gost12_256',
'-verify '.escapeshellarg($publicKeyFile),
'-signature '.escapeshellarg($signatureFile),
escapeshellarg($messageFile),
]);

unlink($certificateFile);
unlink($publicKeyFile);
unlink($signatureFile);
unlink($messageFile);

return 0 == $code;
}

private function runParameters(array $parameters)
{
array_unshift($parameters, $this->toolPath);
exec(implode(' ', $parameters), $output, $code);
return $code;
}
}
8 changes: 6 additions & 2 deletions src/Token/EsiaAccessToken.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class EsiaAccessToken extends AccessToken implements ScopedTokenInterface
{
private $parsedToken;

public function __construct(array $options = [], $publicKeyPath = null)
public function __construct(array $options = [], $publicKeyPath = null, $signer = null)
{
parent::__construct($options);

Expand All @@ -29,7 +29,11 @@ public function __construct(array $options = [], $publicKeyPath = null)
return;
}

if (!$this->parsedToken->verify(new Sha256(), new Key(file_get_contents($publicKeyPath)))) {
if (null == $signer) {
$signer = new Sha256();
}

if (!$this->parsedToken->verify($signer, new Key(file_get_contents($publicKeyPath)))) {
throw new InvalidArgumentException('Access token can not be verified: '.var_export($options, true));
}
}
Expand Down

0 comments on commit 3509af1

Please sign in to comment.