Passed
Push — master ( 463105...84cd59 )
by Roberto
04:47
created

PublicKey::createFromContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 12
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 7
nc 1
nop 1
crap 1
1
<?php
2
3
namespace NFePHP\Common\Certificate;
4
5
/**
6
 * Class for management and use of digital certificates A1 (PKCS # 12)
7
 * @category   NFePHP
8
 * @package    NFePHP\Common\PublicKey
9
 * @copyright  Copyright (c) 2008-2016
10
 * @license    http://www.gnu.org/licenses/lesser.html LGPL v3
11
 * @author     Antonio Spinelli <tonicospinelli85 at gmail dot com>
12
 * @link       http://github.com/nfephp-org/sped-common for the canonical source repository
13
 */
14
15
use NFePHP\Common\Exception\CertificateException;
16
use NFePHP\Common\Certificate\Asn1;
17
18
class PublicKey implements VerificationInterface
19
{
20
    /**
21
     * @var string
22
     */
23
    private $rawKey;
24
    /**
25
     * @var string
26
     */
27
    public $commonName;
28
    /**
29
     * @var string
30
     */
31
    public $cnpj;
32
    /**
33
     * @var \DateTime
34
     */
35
    public $validFrom;
36
    /**
37
     * @var \DateTime
38
     */
39
    public $validTo;
40
    /**
41
     * @var string
42
     */
43
    public $emailAddress;
44
    /**
45
     * @var string
46
     */
47
    public $cspName;
48
    /**
49
     * @var string
50
     */
51
    public $serialNumber;
52
53
    /**
54
     * PublicKey constructor.
55
     * @param string $publicKey
56
     */
57 11
    public function __construct($publicKey)
58
    {
59 11
        $this->rawKey = $publicKey;
60 11
        $this->read();
61 11
    }
62
    
63
    /**
64
     * Load class with certificate content
65
     * @param string $content
66
     * @return \static
67
     */
68 1
    public static function createFromContent($content)
69
    {
70 1
        $content = rtrim(chunk_split(preg_replace('/[\r\n]/', '', $content), 64, PHP_EOL));
71
        $certificate = <<<CONTENT
72
-----BEGIN CERTIFICATE-----
73 1
{$content}
74
-----END CERTIFICATE-----
75
76
CONTENT;
77
78 1
        return new static($certificate);
79
    }
80
    
81
    /**
82
     * Parse an X509 certificate and define the information in object
83
     * @link http://php.net/manual/en/function.openssl-x509-read.php
84
     * @link http://php.net/manual/en/function.openssl-x509-parse.php
85
     * @return void
86
     * @throws CertificateException Unable to open certificate
87
     */
88 11
    protected function read()
89
    {
90 11
        if (!$resource = openssl_x509_read($this->rawKey)) {
91
            throw CertificateException::unableToOpen();
92
        }
93 11
        $detail = openssl_x509_parse($resource, false);
94 11
        $this->commonName = $detail['subject']['commonName'];
95 11
        $this->emailAddress = !empty($detail['subject']['emailAddress']) ?
96
            $detail['subject']['emailAddress'] :
97 11
            '';
98 11
        $this->cspName = $detail['issuer']['organizationalUnitName'];
99 11
        $this->serialNumber = $detail['serialNumber'];
100 11
        $this->validFrom = \DateTime::createFromFormat('ymdHis\Z', $detail['validFrom']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DateTime::createFromFor..., $detail['validFrom']) can also be of type false. However, the property $validFrom is declared as type object<DateTime>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
101 11
        $this->validTo = \DateTime::createFromFormat('ymdHis\Z', $detail['validTo']);
0 ignored issues
show
Documentation Bug introduced by
It seems like \DateTime::createFromFor...Z', $detail['validTo']) can also be of type false. However, the property $validTo is declared as type object<DateTime>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
102 11
        $this->cnpj = Asn1::getCNPJ($this->unFormated());
103 11
    }
104
105
    /**
106
     * Verify signature
107
     * @link http://php.net/manual/en/function.openssl-verify.php
108
     * @param string $data
109
     * @param string $signature
110
     * @param int $algorithm [optional] For more information see the list of Signature Algorithms.
111
     * @return int Returns true if the signature is correct, false if it is incorrect
112
     * @throws CertificateException An error has occurred when verify signature
113
     */
114 2
    public function verify($data, $signature, $algorithm = OPENSSL_ALGO_SHA1)
115
    {
116 2
        $verified = openssl_verify($data, $signature, $this->rawKey, $algorithm);
117 2
        if ($verified === static::SIGNATURE_ERROR) {
118
            throw CertificateException::signatureFailed();
119
        }
120 2
        return $verified === static::SIGNATURE_CORRECT;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $verified === static::SIGNATURE_CORRECT; (boolean) is incompatible with the return type declared by the interface NFePHP\Common\Certificat...cationInterface::verify of type integer.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
121
    }
122
123
    /**
124
     * Check if is in valid date interval.
125
     * @return bool Returns true
126
     */
127 3
    public function isExpired()
128
    {
129 3
        return new \DateTime('now') > $this->validTo;
130
    }
131
132
    /**
133
     * Returns raw public key without markers and LF's
134
     * @return string
135
     */
136 11
    public function unFormated()
137
    {
138 11
        $ret = preg_replace('/-----.*[\n]?/', '', $this->rawKey);
139 11
        return preg_replace('/[\n\r]/', '', $ret);
140
    }
141
    
142
    /**
143
     * Returns raw public key
144
     * @return string
145
     */
146 1
    public function __toString()
147
    {
148 1
        return $this->rawKey;
149
    }
150
}
151