Example #1
3
 /**
  * @group github602
  */
 public function testEmptyContextTag()
 {
     $asn1 = new ASN1();
     $decoded = $asn1->decodeBER("�");
     $this->assertInternalType('array', $decoded);
     $this->assertCount(0, $decoded[0]['content']);
 }
Example #2
0
    public function testSaveUnsupportedExtension()
    {
        $x509 = new X509();
        $cert = $x509->loadX509('-----BEGIN CERTIFICATE-----
MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x
MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy
wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B
d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM
BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp
ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
-----END CERTIFICATE-----');
        $asn1 = new ASN1();
        $value = $this->_encodeOID('1.2.3.4');
        $ext = chr(ASN1::TYPE_OBJECT_IDENTIFIER) . $asn1->_encodeLength(strlen($value)) . $value;
        $value = 'zzzzzzzzz';
        $ext .= chr(ASN1::TYPE_OCTET_STRING) . $asn1->_encodeLength(strlen($value)) . $value;
        $ext = chr(ASN1::TYPE_SEQUENCE | 0x20) . $asn1->_encodeLength(strlen($ext)) . $ext;
        $cert['tbsCertificate']['extensions'][4] = new Element($ext);
        $result = $x509->loadX509($x509->saveX509($cert));
        $this->assertCount(5, $result['tbsCertificate']['extensions']);
    }
Example #3
0
 /**
  * @todo This can be simplified once Responses are created by a factory.
  */
 public function testHandleReturnsResponseIfSuccessful()
 {
     $pathToResponderCert = vfsStream::newFile('issuerCert.pem')->at(vfsStream::setUp())->withContent($this->getCertInPem())->url();
     $process = $this->getMockProcess();
     $process->method('isSuccessful')->willReturn(true);
     $process->method('setCommandLine')->will($this->returnCallback(function ($commandLine) {
         // NB! This assumes the outfile is the last argument. If things go
         // south, assume somone has fiddled with the argument order.
         $commandLine = explode('-respout', $commandLine);
         $fileName = trim(end($commandLine), '\' ');
         $parser = new Asn1Parser();
         $asn1 = new Asn1();
         file_put_contents($fileName, $parser->encodeDER(array('responseStatus' => Asn1::OCSP_SUCCESSFUL, 'responseBytes' => array('responseType' => Asn1::OID_ID_PKIX_OCSP_BASIC, 'response' => 'MIICOTCCASGhgYYwgYMxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMQ0wCwYDVQQLDARPQ1NQMScwJQYDVQQDDB5URVNUIG9mIFNLIE9DU1AgUkVTUE9OREVSIDIwMTExGDAWBgkqhkiG9w0BCQEWCXBraUBzay5lZRgPMjAxNDEyMjYyMzE1NDVaMGAwXjBJMAkGBSsOAwIaBQAEFJ8hzI+QiAAqq1ikY3MvViFZKzWuBBR7avJVUFy42XoIh0Gu+qIrPVtXdgIQH/v/rqwJX11SX33gZ4PrfYAAGA8yMDE0MTIyNjIzMTU0NVqhIzAhMB8GCSsGAQUFBzABAgQSBBDXw6pZv+/fMYQlxV3ACvKZMA0GCSqGSIb3DQEBBQUAA4IBAQBxe4hdQYCqR+O5wLFP1nY5HiP4w348YXfFiEvVmC9JCoaoSqmXdoner0sJxYdnOleu7/WdRAvO+hAnl73aOm0l+woGpm1fud8pl7Bz0F8cIiYL4g5xorArkdHZLwMmxi09ZzhBgM93xyOtpUj1c2onIXLEyV4ENv6DPBIAPNOVVTiaeFBVGba7g4RZxgvHWeuO+OmCAezjYJNZfXaYshvudAxaqmrhBCd3xDAYjgQlarhRn6aXpNsVRZG8NK4XW6+rH+4q+9S2ZsA6KTVkfGC218unYUkA0FswJH1JO7D+G9kooZHGIuV7SL5l4bpGwNxcbtdu+xYtNqNr4xSkHBTn')), $asn1->OCSPResponse));
     }));
     $responder = new Responder('http://example.com', $pathToResponderCert, null, $process);
     $response = $responder->handle($this->getMockRequest());
     $this->assertInstanceOf('KG\\DigiDoc\\OCSP\\Response', $response);
 }
Example #4
0
 /**
  * {@inheritdoc}
  */
 protected function supportsKey($key)
 {
     if (false === parent::supportsKey($key)) {
         return false;
     }
     // openssl_sign with EC keys was introduced in this PHP release
     $minVersions = array('5.4' => '5.4.26', '5.5' => '5.5.10', '5.6' => '5.6.0');
     if (isset($minVersions[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION]) && version_compare(PHP_VERSION, $minVersions[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION], '<')) {
         return false;
     }
     $keyDetails = openssl_pkey_get_details($key);
     if (0 === preg_match('/-----BEGIN PUBLIC KEY-----([^-]+)-----END PUBLIC KEY-----/', $keyDetails['key'], $matches)) {
         return false;
     }
     $publicKey = trim($matches[1]);
     $asn1 = new ASN1();
     /*
      * http://tools.ietf.org/html/rfc3279#section-2.2.3
      * AlgorithmIdentifier ::= SEQUENCE {
      *     algorithm OBJECT IDENTIFIER,
      *     parameters ANY DEFINED BY algorithm OPTIONAL
      * }
      * For ECDSA Signature Algorithm:
      * algorithm: ansi-X9-62 => 1.2.840.10045.2.1
      * parameters: id-ecSigType => 1.2.840.10045.x.y.z
      *
      */
     $asnAlgorithmIdentifier = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('ansi-X9-62' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER), 'id-ecSigType' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER)));
     /*
      * http://tools.ietf.org/html/rfc5280#section-4.1
      * SubjectPublicKeyInfo ::= SEQUENCE {
      *     algorithm AlgorithmIdentifier,
      *     subjectPublicKey BIT STRING
      * }
      */
     $asnSubjectPublicKeyInfo = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('algorithm' => $asnAlgorithmIdentifier, 'subjectPublicKey' => array('type' => ASN1::TYPE_BIT_STRING)));
     $decoded = $asn1->decodeBER(base64_decode($publicKey));
     $mappedDetails = $asn1->asn1map($decoded[0], $asnSubjectPublicKeyInfo);
     return isset($mappedDetails['algorithm']['id-ecSigType']) ? $this->getSupportedECDSACurve() === $mappedDetails['algorithm']['id-ecSigType'] : false;
 }
Example #5
0
 /**
  * Wrap a public key appropriately
  *
  * @access public
  * @param string $key
  * @return string
  */
 static function wrapPublicKey($key, $algorithm)
 {
     $asn1 = new ASN1();
     $key = ['publicKeyAlgorithm' => ['algorithm' => $algorithm, 'parameters' => null], 'publicKey' => Base64::encode("" . $key)];
     $key = $asn1->encodeDER($key, PublicKeyInfo);
     return "-----BEGIN PUBLIC KEY-----\r\n" . chunk_split(Base64::encode($key), 64) . "-----END PUBLIC KEY-----";
 }
Example #6
0
    /**
     * Compute a public key identifier.
     *
     * Although key identifiers may be set to any unique value, this function
     * computes key identifiers from public key according to the two
     * recommended methods (4.2.1.2 RFC 3280).
     * Highly polymorphic: try to accept all possible forms of key:
     * - Key object
     * - \phpseclib\File\X509 object with public or private key defined
     * - Certificate or CSR array
     * - \phpseclib\File\ASN1\Element object
     * - PEM or DER string
     *
     * @param mixed $key optional
     * @param int $method optional
     * @access public
     * @return string binary key identifier
     */
    function computeKeyIdentifier($key = null, $method = 1)
    {
        if (is_null($key)) {
            $key = $this;
        }

        switch (true) {
            case is_string($key):
                break;
            case is_array($key) && isset($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
                return $this->computeKeyIdentifier($key['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $method);
            case is_array($key) && isset($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
                return $this->computeKeyIdentifier($key['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $method);
            case !is_object($key):
                return false;
            case $key instanceof Element:
                // Assume the element is a bitstring-packed key.
                $asn1 = new ASN1();
                $decoded = $asn1->decodeBER($key->element);
                if (empty($decoded)) {
                    return false;
                }
                $raw = $asn1->asn1map($decoded[0], array('type' => ASN1::TYPE_BIT_STRING));
                if (empty($raw)) {
                    return false;
                }
                $raw = base64_decode($raw);
                // If the key is private, compute identifier from its corresponding public key.
                $key = new RSA();
                if (!$key->loadKey($raw)) {
                    return false;   // Not an unencrypted RSA key.
                }
                if ($key->getPrivateKey() !== false) {  // If private.
                    return $this->computeKeyIdentifier($key, $method);
                }
                $key = $raw;    // Is a public key.
                break;
            case $key instanceof X509:
                if (isset($key->publicKey)) {
                    return $this->computeKeyIdentifier($key->publicKey, $method);
                }
                if (isset($key->privateKey)) {
                    return $this->computeKeyIdentifier($key->privateKey, $method);
                }
                if (isset($key->currentCert['tbsCertificate']) || isset($key->currentCert['certificationRequestInfo'])) {
                    return $this->computeKeyIdentifier($key->currentCert, $method);
                }
                return false;
            default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA).
                $key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
                break;
        }

        // If in PEM format, convert to binary.
        $key = $this->_extractBER($key);

        // Now we have the key string: compute its sha-1 sum.
        $hash = new Hash('sha1');
        $hash = $hash->hash($key);

        if ($method == 2) {
            $hash = substr($hash, -8);
            $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40);
        }

        return $hash;
    }
Example #7
0
 /**
  * Decodes and maps the BasicOCSPResponse part of the response.
  *
  * @return array
  */
 private function getResponseMapped()
 {
     $parser = new Asn1Parser();
     $responseBasicDecoded = $parser->decodeBER(base64_decode($this->response));
     return $parser->asn1map($responseBasicDecoded[0], $this->asn1->BasicOCSPResponse);
 }
Example #8
0
 /**
  * Convert a public key to the appropriate format
  *
  * @access public
  * @param \phpseclib\Math\BigInteger $n
  * @param \phpseclib\Math\BigInteger $e
  * @return string
  */
 static function savePublicKey(BigInteger $n, BigInteger $e)
 {
     $key = ['modulus' => $n, 'publicExponent' => $e];
     $asn1 = new ASN1();
     $key = $asn1->encodeDER($key, RSAPublicKey);
     return self::wrapPublicKey($key, 'RSA');
 }
Example #9
0
 /**
  * Convert a public key to the appropriate format
  *
  * @access public
  * @param \phpseclib\Math\BigInteger $n
  * @param \phpseclib\Math\BigInteger $e
  * @return string
  */
 static function savePublicKey(BigInteger $n, BigInteger $e)
 {
     $key = PKCS1::savePublicKey($n, $e);
     $key = ASN1::extractBER($key);
     return self::wrapPublicKey($key, '1.2.840.113549.1.1.1');
 }
Example #10
0
 /**
  * RSASSA-PKCS1-V1_5-VERIFY (relaxed matching)
  *
  * Per {@link http://tools.ietf.org/html/rfc3447#page-43 RFC3447#page-43} PKCS1 v1.5
  * specified the use BER encoding rather than DER encoding that PKCS1 v2.0 specified.
  * This means that under rare conditions you can have a perfectly valid v1.5 signature
  * that fails to validate with _rsassa_pkcs1_v1_5_verify(). PKCS1 v2.1 also recommends
  * that if you're going to validate these types of signatures you "should indicate
  * whether the underlying BER encoding is a DER encoding and hence whether the signature
  * is valid with respect to the specification given in [PKCS1 v2.0+]". so if you do
  * $rsa->getLastPadding() and get RSA::PADDING_RELAXED_PKCS1 back instead of
  * RSA::PADDING_PKCS1... that means BER encoding was used.
  *
  * @access private
  * @param string $m
  * @param string $s
  * @return bool
  */
 function _rsassa_pkcs1_v1_5_relaxed_verify($m, $s)
 {
     // Length checking
     if (strlen($s) != $this->k) {
         return false;
     }
     // RSA verification
     $s = $this->_os2ip($s);
     $m2 = $this->_rsavp1($s);
     if ($m2 === false) {
         return false;
     }
     $em = $this->_i2osp($m2, $this->k);
     if ($em === false) {
         return false;
     }
     if ($this->_string_shift($em, 2) != "") {
         return false;
     }
     $em = ltrim($em, "ÿ");
     if ($this->_string_shift($em) != "") {
         return false;
     }
     $asn1 = new ASN1();
     $decoded = $asn1->decodeBER($em);
     if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) {
         return false;
     }
     $AlgorithmIdentifier = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('algorithm' => array('type' => ASN1::TYPE_OBJECT_IDENTIFIER), 'parameters' => array('type' => ASN1::TYPE_ANY, 'optional' => true)));
     $DigestInfo = array('type' => ASN1::TYPE_SEQUENCE, 'children' => array('digestAlgorithm' => $AlgorithmIdentifier, 'digest' => array('type' => ASN1::TYPE_OCTET_STRING)));
     $oids = array('1.2.840.113549.2.2' => 'md2', '1.2.840.113549.2.4' => 'md4', '1.2.840.113549.2.5' => 'md5', '1.3.14.3.2.26' => 'sha1', '2.16.840.1.101.3.4.2.1' => 'sha256', '2.16.840.1.101.3.4.2.2' => 'sha384', '2.16.840.1.101.3.4.2.3' => 'sha512');
     $asn1->loadOIDs($oids);
     $decoded = $asn1->asn1map($decoded[0], $DigestInfo);
     if (!isset($decoded) || $decoded === false) {
         return false;
     }
     if (!in_array($decoded['digestAlgorithm']['algorithm'], $oids)) {
         return false;
     }
     $hash = new Hash($decoded['digestAlgorithm']['algorithm']);
     $em = $hash->hash($m);
     $em2 = Base64::decode($decoded['digest']);
     return $this->_equals($em, $em2);
 }
Example #11
0
 /**
  * Break a public or private key down into its constituent components
  *
  * @access public
  * @param string $key
  * @param string $password optional
  * @return array
  */
 static function load($key, $password)
 {
     if (!is_string($key)) {
         return false;
     }
     /* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
                "outside the scope" of PKCS#1.  PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
                protect private keys, however, that's not what OpenSSL* does.  OpenSSL protects private keys by adding
                two new "fields" to the key - DEK-Info and Proc-Type.  These fields are discussed here:
     
                http://tools.ietf.org/html/rfc1421#section-4.6.1.1
                http://tools.ietf.org/html/rfc1421#section-4.6.1.3
     
                DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
                DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
                function.  As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
                own implementation.  ie. the implementation *is* the standard and any bugs that may exist in that
                implementation are part of the standard, as well.
     
                * OpenSSL is the de facto standard.  It's utilized by OpenSSH and other projects */
     if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
         $iv = Hex::decode(trim($matches[2]));
         // remove the Proc-Type / DEK-Info sections as they're no longer needed
         $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
         $ciphertext = ASN1::extractBER($key);
         if ($ciphertext === false) {
             $ciphertext = $key;
         }
         $crypto = self::getEncryptionObject($matches[1]);
         $crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
         $crypto->setIV($iv);
         $key = $crypto->decrypt($ciphertext);
     } else {
         if (self::$format != self::MODE_DER) {
             $decoded = ASN1::extractBER($key);
             if ($decoded !== false) {
                 $key = $decoded;
             } elseif (self::$format == self::MODE_PEM) {
                 return false;
             }
         }
     }
     return $key;
 }
Example #12
0
 /**
  * @param $publicKey
  *
  * @return array|bool
  */
 protected static function loadPublicKey($publicKey)
 {
     $asn1 = new ASN1();
     $asnAlgorithmIdentifier = ['type' => ASN1::TYPE_SEQUENCE, 'children' => ['ansi-X9-62' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER], 'id-ecSigType' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]]];
     $asnSubjectPublicKeyInfo = ['type' => ASN1::TYPE_SEQUENCE, 'children' => ['algorithm' => $asnAlgorithmIdentifier, 'subjectPublicKey' => ['type' => ASN1::TYPE_BIT_STRING]]];
     $decoded = $asn1->decodeBER(base64_decode($publicKey));
     $mappedDetails = $asn1->asn1map($decoded[0], $asnSubjectPublicKeyInfo);
     if (null === $mappedDetails) {
         return false;
     }
     $details = Base64Url::decode($mappedDetails['subjectPublicKey']);
     if (!self::isAlgorithmSupported($mappedDetails['algorithm']['id-ecSigType'])) {
         return false;
     }
     if (substr($details, 0, 1) !== "") {
         return false;
     }
     if (substr($details, 1, 1) !== "") {
         return false;
     }
     $X = substr($details, 2, (strlen($details) - 2) / 2);
     $Y = substr($details, (strlen($details) - 2) / 2 + 2, (strlen($details) - 2) / 2);
     return ['x' => Base64Url::encode($X), 'y' => Base64Url::encode($Y)];
 }
Example #13
0
 /**
  * Creates a DER response for testing
  *
  * @param mixed $source
  *
  * @return string
  */
 private function createDerResponse($source)
 {
     $parser = new Asn1Parser();
     $asn1 = new Asn1();
     return $parser->encodeDER($source, $asn1->OCSPResponse);
 }
Example #14
0
 /**
  * Set certificate end date
  *
  * @param String $date
  *
  * @access public
  */
 function setEndDate($date)
 {
     /*
       To indicate that a certificate has no well-defined expiration date,
       the notAfter SHOULD be assigned the GeneralizedTime value of
       99991231235959Z.
     
       -- http://tools.ietf.org/html/rfc5280#section-4.1.2.5
     */
     if (strtolower($date) == 'lifetime') {
         $temp = '99991231235959Z';
         $asn1 = new ASN1();
         $temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
         $this->endDate = new Element($temp);
     } else {
         $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
     }
 }