Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .scrutinizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ filter:
- 'vendor/'

build:
dependencies:
override:
- composer self-update --no-interaction --no-progress
- composer remove squizlabs/php_codesniffer friendsofphp/php-cs-fixer phpstan/phpstan --dev --no-interaction --no-progress --no-update
- composer install --no-interaction
nodes:
php:
tests:
Expand Down
13 changes: 2 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
language: php

# php compatibility
php: ["7.2", "7.3", "7.4snapshot"]

matrix:
allow_failures:
- php: "7.4snapshot"

env:
global:
- PHP_CS_FIXER_FUTURE_MODE=1
- PHP_CS_FIXER_IGNORE_ENV=1
php: ["7.2", "7.3", "7.4"]

cache:
- directories:
Expand All @@ -24,7 +15,7 @@ script:
- vendor/bin/php-cs-fixer fix --verbose
- vendor/bin/phpcbf --colors -sp src/ tests/
- vendor/bin/phpunit --testdox --verbose
- vendor/bin/phpstan.phar analyse --no-progress --verbose --level max src/ tests/
- vendor/bin/phpstan analyse --no-progress --verbose --level max src/ tests/

notifications:
email: false
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,5 +78,5 @@ Before you can run these, be sure to `composer install` or `composer update`.
vendor/bin/phpcs -sp src/ tests/
vendor/bin/php-cs-fixer fix -v --dry-run
vendor/bin/phpunit --coverage-text
vendor/bin/phpstan.phar analyse --no-progress --level max src/ tests/
vendor/bin/phpstan analyse --no-progress --level max src/ tests/
```
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2019 PHPCFDI
Copyright (c) 2019 - 2020 PHPCFDI

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
14 changes: 4 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ así como de la llave pública.
- La FIEL (o eFirma) es utilizada para firmar electrónicamente documentos (generalmente usando XML-SEC) y
está reconocida por el gobierno mexicano como una manera de firma legal de una persona física o moral.

Con esta librería no es necesario convertir los archivos generados por el SAT a otro formato,
se pueden utilizar tal y como el SAT los entrega.

## Instalación

Expand All @@ -32,7 +34,6 @@ Usa [composer](https://getcomposer.org/)
composer require phpcfdi/credentials
```


## Ejemplo básico de uso

```php
Expand All @@ -59,10 +60,8 @@ echo $certificado->rfc(), PHP_EOL; // el RFC del certificado
echo $certificado->legalName(), PHP_EOL; // el nombre del propietario del certificado
echo $certificado->branchName(), PHP_EOL; // el nombre de la sucursal (en CSD, en FIEL está vacía)
echo $certificado->serialNumber()->bytes(), PHP_EOL; // número de serie del certificado

```


## Acerca de los archivos de certificado y llave privada

Los archivos de certificado vienen en formato `X.509 DER` y los de llave privada en formato `PKCS#8 DER`.
Expand All @@ -75,7 +74,6 @@ a `base64`, en renglones de 64 caracteres y con cabeceras específicas para cert
De esta forma, para usar el certificado `AAA010101AAA.cer` o la llave privada `AAA010101AAA.key` provistos por
el SAT, no es necesario convertirlos con `openssl` y la librería los detectará correctamente.


### Crear un objeto de certificado `Certificate`

El objeto `Certificate` no se creará si contiene datos no válidos.
Expand All @@ -91,7 +89,6 @@ o en las firmas XML, por este motivo, los formatos soportados para crear un obje
- Si `$content` está totalmente en `base64`, se interpreta como `X.509 DER base64` y se formatea a `X.509 PEM`
- En otro caso, se interpreta como formato `X.509 DER`, por lo que se formatea a `X.509 PEM`.


### Crear un objeto de llave privada `PrivateKey`

El objeto `PrivateKey` no se creará si contiene datos no válidos.
Expand All @@ -118,7 +115,6 @@ Notas de tratamiento de archivos `DER`:
Para entender más de los formatos de llaves privadas se puede consultar la siguiente liga:
<https://github.com/kjur/jsrsasign/wiki/Tutorial-for-PKCS5-and-PKCS8-PEM-private-key-formats-differences>


## Compatilibilidad

Esta librería se mantendrá compatible con al menos la versión con
Expand All @@ -127,13 +123,11 @@ Esta librería se mantendrá compatible con al menos la versión con
También utilizamos [Versionado Semántico 2.0.0](https://semver.org/lang/es/) por lo que puedes usar esta librería
sin temor a romper tu aplicación.


## Contribuciones

Las contribuciones con bienvenidas. Por favor lee [CONTRIBUTING][] para más detalles
y recuerda revisar el archivo de tareas pendientes [TODO][] y el [CHANGELOG][].


## Copyright and License

The phpcfdi/finkok library is copyright © [PhpCfdi](https://github.com/phpcfdi)
Expand All @@ -146,15 +140,15 @@ and licensed for use under the MIT License (MIT). Please see [LICENSE][] for mor
[source]: https://github.com/phpcfdi/credentials
[release]: https://github.com/phpcfdi/credentials/releases
[license]: https://github.com/phpcfdi/credentials/blob/master/LICENSE
[build]: https://travis-ci.org/phpcfdi/credentials?branch=master
[build]: https://travis-ci.com/phpcfdi/credentials?branch=master
[quality]: https://scrutinizer-ci.com/g/phpcfdi/credentials/
[coverage]: https://scrutinizer-ci.com/g/phpcfdi/credentials/code-structure/master/code-coverage/src/
[downloads]: https://packagist.org/packages/phpcfdi/credentials

[badge-source]: https://img.shields.io/badge/source-phpcfdi/credentials-blue?style=flat-square
[badge-release]: https://img.shields.io/github/release/phpcfdi/credentials?style=flat-square
[badge-license]: https://img.shields.io/github/license/phpcfdi/credentials?style=flat-square
[badge-build]: https://img.shields.io/travis/phpcfdi/credentials/master?style=flat-square
[badge-build]: https://img.shields.io/travis/com/phpcfdi/credentials/master?style=flat-square
[badge-quality]: https://img.shields.io/scrutinizer/g/phpcfdi/credentials/master?style=flat-square
[badge-coverage]: https://img.shields.io/scrutinizer/coverage/g/phpcfdi/credentials/master?style=flat-square
[badge-downloads]: https://img.shields.io/packagist/dt/phpcfdi/credentials?style=flat-square
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"phpunit/phpunit": "^8.4",
"squizlabs/php_codesniffer": "^3.0",
"friendsofphp/php-cs-fixer": "^2.4",
"phpstan/phpstan-shim": "^0.11"
"phpstan/phpstan": "^0.12"
},
"autoload": {
"psr-4": {
Expand Down
10 changes: 10 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@

Nos apegamos a [SEMVER](SEMVER.md), revisa la información para entender mejor el control de versiones.

## Version 1.1.1 2020-01-22

- Weak Break Compatibility Change: `PemExtractor::__construct($contents)` se podría construir con un parámetro de
cualquier tipo de datos y al intentar usar el objeto inevitablemente iba a generar un `TypeError`. Se cambió la
firma del constructor a `PemExtractor::__construct(string $contents)`, así fallaría desde construir el objeto y
no al usar cualquiera de sus métodos.
- Se actualiza la licencia a 2020.
- Se actualiza de `phpstan/phpstan-shim: ^0.11` a `phpstan/phpstan: ^0.12`.
- Se actualiza la integración continua en Travis y Scrutinizer.

## Version 1.1.0 2019-11-19

- Se puede crear una llave privada en formato `PKCS#8 DER` encriptada o desprotegida.
Expand Down
9 changes: 8 additions & 1 deletion src/Certificate.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public function __construct(string $contents)
$pem = static::convertDerToPem($contents);
}

/** @var array|false $parsed */
/** @var array<mixed>|false $parsed */
$parsed = openssl_x509_parse($pem, true);
if (false === $parsed) {
throw new UnexpectedValueException('Cannot parse X509 certificate from contents');
Expand Down Expand Up @@ -95,6 +95,9 @@ public function pemAsOneLine(): string
return implode('', preg_grep('/^((?!-).)*$/', explode(PHP_EOL, $this->pem())));
}

/**
* @return array<mixed>
*/
public function parsed(): array
{
return $this->dataArray;
Expand All @@ -120,6 +123,7 @@ public function name(): string
return $this->extractString('name');
}

/** @return array<string, string> */
public function subject(): array
{
return $this->extractArray('subject');
Expand All @@ -135,6 +139,7 @@ public function hash(): string
return $this->extractString('hash');
}

/** @return array<string, string> */
public function issuer(): array
{
return $this->extractArray('issuer');
Expand Down Expand Up @@ -196,11 +201,13 @@ public function signatureTypeNID(): string
return $this->extractString('signatureTypeNID');
}

/** @return array<mixed> */
public function purposes(): array
{
return $this->extractArray('purposes');
}

/** @return array<string, string> */
public function extensions(): array
{
return $this->extractArray('extensions');
Expand Down
4 changes: 2 additions & 2 deletions src/Credential.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function __construct(Certificate $certificate, PrivateKey $privateKey)
* @param string $certificateContents
* @param string $privateKeyContents
* @param string $passPhrase
* @return static
* @return self
*/
public static function create(string $certificateContents, string $privateKeyContents, string $passPhrase): self
{
Expand All @@ -58,7 +58,7 @@ public static function create(string $certificateContents, string $privateKeyCon
* @param string $certificateFile
* @param string $privateKeyFile
* @param string $passPhrase
* @return static
* @return self
*/
public static function openFiles(string $certificateFile, string $privateKeyFile, string $passPhrase): self
{
Expand Down
13 changes: 11 additions & 2 deletions src/Internal/DataArrayTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@
/** @internal */
trait DataArrayTrait
{
/** @var array content of openssl_x509_parse */
/** @var array<mixed> content of openssl_x509_parse or openssl_pkey_get_details */
protected $dataArray;

/**
* @param string $key
* @param string|int|float|bool $default
* @return string|int|float|bool
*/
protected function extractScalar(string $key, $default)
{
$value = $this->dataArray[$key] ?? $default;
Expand All @@ -35,7 +40,11 @@ protected function extractInteger(string $key): int
return 0;
}

protected function extractArray(string $key):array
/**
* @param string $key
* @return array<mixed>
*/
protected function extractArray(string $key): array
{
$data = $this->dataArray[$key] ?? null;
if (! is_array($data)) {
Expand Down
3 changes: 3 additions & 0 deletions src/Internal/Key.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ class Key
/** @var OpenSslKeyTypeEnum|null */
private $type;

/** @param array<mixed> $dataArray */
public function __construct($dataArray)
{
$this->dataArray = $dataArray;
}

/** @return array<mixed> */
public function parsed(): array
{
return $this->dataArray;
Expand All @@ -40,6 +42,7 @@ public function type(): OpenSslKeyTypeEnum
return $this->type;
}

/** @return array<mixed> */
public function typeData(): array
{
return $this->extractArray($this->type()->value());
Expand Down
9 changes: 7 additions & 2 deletions src/Internal/OpenSslKeyTypeEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@
*
* @internal
*/
class OpenSslKeyTypeEnum extends Enum
final class OpenSslKeyTypeEnum extends Enum
{
/** @noinspection PhpUnused */
/**
* Override indices to use OPENSSL constants as indices
*
* @noinspection PhpUnused
* @return array<string, int>
*/
protected static function overrideIndices(): array
{
return [
Expand Down
4 changes: 4 additions & 0 deletions src/Internal/Rfc4514.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ public function escape(string $subject): string
return $prefix . str_replace(self::INNER_CHARS, self::INNER_REPLACEMENTS, $subject) . $sufix;
}

/**
* @param array<string, string> $values
* @return string
*/
public function escapeArray(array $values): string
{
return implode(',', array_map(
Expand Down
2 changes: 1 addition & 1 deletion src/PemExtractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class PemExtractor
/** @var string */
private $contents;

public function __construct($contents)
public function __construct(string $contents)
{
$this->contents = $contents;
}
Expand Down
4 changes: 2 additions & 2 deletions src/PrivateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class PrivateKey extends Key
/** @var string */
private $passPhrase;

/** @var PublicKey|null $public key extracted from private key */
/** @var PublicKey|null public key extracted from private key */
private $publicKey;

/**
Expand Down Expand Up @@ -73,7 +73,7 @@ public static function convertDerToPem(string $contents, bool $isEncrypted): str
*
* @param string $filename must be a local file (without scheme or file:// scheme)
* @param string $passPhrase
* @return static
* @return self
*/
public static function openFile(string $filename, string $passPhrase): self
{
Expand Down
6 changes: 6 additions & 0 deletions src/PublicKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ protected function openSslVerify(string $data, string $signature, $publicKey, in
return openssl_verify($data, $signature, $publicKey, $algorithm);
}

/**
* Run a clousure with this public key opened
*
* @param Closure $function
* @return mixed
*/
public function callOnPublicKey(Closure $function)
{
return $this->callOnPublicKeyWithContents($function, $this->publicKeyContents());
Expand Down
8 changes: 4 additions & 4 deletions tests/Unit/CertificateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ public function testSignature(): void
public function testCreateSerialNumber(): void
{
$reflection = new \ReflectionClass(Certificate::class);
$createSerialNumberMethod = $reflection->getMethod('createSerialNumber');
$createSerialNumberMethod->setAccessible(true);
$reflectionMethod = $reflection->getMethod('createSerialNumber');
$reflectionMethod->setAccessible(true);
$certificate = $reflection->newInstanceWithoutConstructor();
$createSerialNumber = function ($hexadecimal, $decimal) use ($certificate, $createSerialNumberMethod): SerialNumber {
return $createSerialNumberMethod->invoke($certificate, $hexadecimal, $decimal);
$createSerialNumber = function ($hexadecimal, $decimal) use ($certificate, $reflectionMethod): SerialNumber {
return $reflectionMethod->invoke($certificate, $hexadecimal, $decimal);
};

/** @var SerialNumber $serialNumber */
Expand Down
1 change: 1 addition & 0 deletions tests/Unit/Internal/DataArrayTraitSpecimen.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class DataArrayTraitSpecimen
DataArrayTrait::extractDateTime as public;
}

/** @param array<mixed> $dataArray */
public function __construct(array $dataArray)
{
$this->dataArray = $dataArray;
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Internal/Rfc4514Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ public function testEscapeArray(): void
$this->assertSame($expected, $object->escapeArray($subject));
}

public function providerEscape()
/** @return array<string, array<string>> */
public function providerEscape(): array
{
return [
'normal' => ['foo bar', 'foo bar'],
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/PemExtractorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public function testExtractorWithEmptyContent(): void
$this->assertSame('', $extractor->extractCertificate());
}

public function providerCrLfAndLf()
/** @return array<string, array<string>> */
public function providerCrLfAndLf(): array
{
return [
'CRLF' => ["\r\n"],
Expand Down