Move to more PSR-4 standards.
This commit is contained in:
210
lib/OpenPgP/PublicKeyPacket.php
Normal file
210
lib/OpenPgP/PublicKeyPacket.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace Leenooks\OpenPGP;
|
||||
|
||||
use Leenooks\OpenPGP;
|
||||
|
||||
/**
|
||||
* OpenPGP Public-Key packet (tag 6).
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-5.5.1.1
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-5.5.2
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-11.1
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-12
|
||||
*/
|
||||
class PublicKeyPacket extends Packet
|
||||
{
|
||||
protected $tag = 6;
|
||||
public $version, $timestamp, $algorithm;
|
||||
public $key, $key_id, $fingerprint;
|
||||
public $v3_days_of_validity;
|
||||
|
||||
static $key_fields = array(
|
||||
1 => array('n', 'e'), // RSA
|
||||
16 => array('p', 'g', 'y'), // ELG-E
|
||||
17 => array('p', 'q', 'g', 'y'), // DSA
|
||||
);
|
||||
|
||||
static $algorithms = [
|
||||
1 => 'RSA',
|
||||
2 => 'RSA',
|
||||
3 => 'RSA',
|
||||
16 => 'ELGAMAL',
|
||||
17 => 'DSA',
|
||||
18 => 'ECC',
|
||||
19 => 'ECDSA',
|
||||
21 => 'DH'
|
||||
];
|
||||
|
||||
function __construct($key=[],$algorithm='RSA',$timestamp=NULL,$version=4)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
if ($key instanceof PublicKeyPacket) {
|
||||
$this->algorithm = $key->algorithm;
|
||||
$this->key = array();
|
||||
|
||||
// Restrict to only the fields we need
|
||||
foreach (self::$key_fields[$this->algorithm] as $field) {
|
||||
$this->key[$field] = $key->key[$field];
|
||||
}
|
||||
|
||||
$this->key_id = $key->key_id;
|
||||
$this->fingerprint = $key->fingerprint;
|
||||
$this->timestamp = $key->timestamp;
|
||||
$this->version = $key->version;
|
||||
$this->v3_days_of_validity = $key->v3_days_of_validity;
|
||||
|
||||
} else {
|
||||
$this->key = $key;
|
||||
if (is_string($this->algorithm = $algorithm)) {
|
||||
$this->algorithm = array_search($this->algorithm,self::$algorithms);
|
||||
}
|
||||
|
||||
$this->timestamp = $timestamp ? $timestamp : time();
|
||||
$this->version = $version;
|
||||
|
||||
if (count($this->key) > 0) {
|
||||
$this->key_id = substr($this->fingerprint(),-8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function body()
|
||||
{
|
||||
switch ($this->version) {
|
||||
case 2:
|
||||
case 3:
|
||||
return implode('', array_merge(array(
|
||||
chr($this->version) . pack('N', $this->timestamp) .
|
||||
pack('n', $this->v3_days_of_validity) . chr($this->algorithm)
|
||||
), $this->fingerprint_material())
|
||||
);
|
||||
|
||||
case 4:
|
||||
return implode('', array_slice($this->fingerprint_material(), 2));
|
||||
}
|
||||
}
|
||||
|
||||
// Find expiry time of this key based on the self signatures in a message
|
||||
function expires($message)
|
||||
{
|
||||
foreach ($this->self_signatures($message) as $p) {
|
||||
foreach (array_merge($p->hashed_subpackets, $p->unhashed_subpackets) as $s) {
|
||||
if ($s instanceof SignaturePacket\KeyExpirationTimePacket) {
|
||||
return $this->timestamp + $s->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Never expires
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-12.2
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-3.3
|
||||
*/
|
||||
function fingerprint()
|
||||
{
|
||||
switch ($this->version) {
|
||||
case 2:
|
||||
case 3:
|
||||
return $this->fingerprint = strtoupper(md5(implode('', $this->fingerprint_material())));
|
||||
|
||||
case 4:
|
||||
return $this->fingerprint = strtoupper(sha1(implode('', $this->fingerprint_material())));
|
||||
}
|
||||
}
|
||||
|
||||
function fingerprint_material()
|
||||
{
|
||||
switch ($this->version) {
|
||||
case 3:
|
||||
$material = array();
|
||||
foreach (self::$key_fields[$this->algorithm] as $i) {
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
}
|
||||
return $material;
|
||||
|
||||
case 4:
|
||||
$head = array(
|
||||
chr(0x99), NULL,
|
||||
chr($this->version), pack('N', $this->timestamp),
|
||||
chr($this->algorithm),
|
||||
);
|
||||
$material = [];
|
||||
foreach (self::$key_fields[$this->algorithm] as $i) {
|
||||
$material[] = pack('n', OpenPGP::bitlength($this->key[$i]));
|
||||
$material[] = $this->key[$i];
|
||||
}
|
||||
|
||||
$material = implode('', $material);
|
||||
$head[1] = pack('n', 6 + strlen($material));
|
||||
$head[] = $material;
|
||||
|
||||
return $head;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-5.5.2
|
||||
*/
|
||||
function read()
|
||||
{
|
||||
switch ($this->version = ord($this->read_byte())) {
|
||||
case 3:
|
||||
$this->timestamp = $this->read_timestamp();
|
||||
$this->v3_days_of_validity = $this->read_unpacked(2, 'n');
|
||||
$this->algorithm = ord($this->read_byte());
|
||||
$this->read_key_material();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$this->timestamp = $this->read_timestamp();
|
||||
$this->algorithm = ord($this->read_byte());
|
||||
$this->read_key_material();
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see http://tools.ietf.org/html/rfc4880#section-5.5.2
|
||||
*/
|
||||
function read_key_material()
|
||||
{
|
||||
foreach (self::$key_fields[$this->algorithm] as $field) {
|
||||
$this->key[$field] = $this->read_mpi();
|
||||
}
|
||||
|
||||
$this->key_id = substr($this->fingerprint(), -8);
|
||||
}
|
||||
|
||||
// Find self signatures in a message, these often contain metadata about the key
|
||||
function self_signatures($message)
|
||||
{
|
||||
$sigs = [];
|
||||
$keyid16 = strtoupper(substr($this->fingerprint,-16));
|
||||
|
||||
foreach ($message as $p) {
|
||||
if ($p instanceof OpenPGP\SignaturePacket) {
|
||||
if (strtoupper($p->issuer()) == $keyid16) {
|
||||
$sigs[] = $p;
|
||||
|
||||
} else {
|
||||
foreach (array_merge($p->hashed_subpackets, $p->unhashed_subpackets) as $s) {
|
||||
if ($s instanceof SignaturePacket\EmbeddedSignaturePacket && strtoupper($s->issuer()) == $keyid16) {
|
||||
$sigs[] = $p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After we've seen a self sig, the next non-sig stop all self-sigs
|
||||
} elseif (count($sigs))
|
||||
break;
|
||||
}
|
||||
|
||||
return $sigs;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user