diff options
Diffstat (limited to 'libs/phpseclib-1.0.4/phpseclib/File/X509.php')
-rw-r--r-- | libs/phpseclib-1.0.4/phpseclib/File/X509.php | 4884 |
1 files changed, 0 insertions, 4884 deletions
diff --git a/libs/phpseclib-1.0.4/phpseclib/File/X509.php b/libs/phpseclib-1.0.4/phpseclib/File/X509.php deleted file mode 100644 index 040551f..0000000 --- a/libs/phpseclib-1.0.4/phpseclib/File/X509.php +++ /dev/null @@ -1,4884 +0,0 @@ -<?php - -/** - * Pure-PHP X.509 Parser - * - * PHP versions 4 and 5 - * - * Encode and decode X.509 certificates. - * - * The extensions are from {@link http://tools.ietf.org/html/rfc5280 RFC5280} and - * {@link http://web.archive.org/web/19961027104704/http://www3.netscape.com/eng/security/cert-exts.html Netscape Certificate Extensions}. - * - * Note that loading an X.509 certificate and resaving it may invalidate the signature. The reason being that the signature is based on a - * portion of the certificate that contains optional parameters with default values. ie. if the parameter isn't there the default value is - * used. Problem is, if the parameter is there and it just so happens to have the default value there are two ways that that parameter can - * be encoded. It can be encoded explicitly or left out all together. This would effect the signature value and thus may invalidate the - * the certificate all together unless the certificate is re-signed. - * - * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * @category File - * @package File_X509 - * @author Jim Wigginton <terrafrost@php.net> - * @copyright 2012 Jim Wigginton - * @license http://www.opensource.org/licenses/mit-license.html MIT License - * @link http://phpseclib.sourceforge.net - */ - -/** - * Include File_ASN1 - */ -if (!class_exists('File_ASN1')) { - include_once 'ASN1.php'; -} - -/** - * Flag to only accept signatures signed by certificate authorities - * - * Not really used anymore but retained all the same to suppress E_NOTICEs from old installs - * - * @access public - */ -define('FILE_X509_VALIDATE_SIGNATURE_BY_CA', 1); - -/**#@+ - * @access public - * @see self::getDN() - */ -/** - * Return internal array representation - */ -define('FILE_X509_DN_ARRAY', 0); -/** - * Return string - */ -define('FILE_X509_DN_STRING', 1); -/** - * Return ASN.1 name string - */ -define('FILE_X509_DN_ASN1', 2); -/** - * Return OpenSSL compatible array - */ -define('FILE_X509_DN_OPENSSL', 3); -/** - * Return canonical ASN.1 RDNs string - */ -define('FILE_X509_DN_CANON', 4); -/** - * Return name hash for file indexing - */ -define('FILE_X509_DN_HASH', 5); -/**#@-*/ - -/**#@+ - * @access public - * @see self::saveX509() - * @see self::saveCSR() - * @see self::saveCRL() - */ -/** - * Save as PEM - * - * ie. a base64-encoded PEM with a header and a footer - */ -define('FILE_X509_FORMAT_PEM', 0); -/** - * Save as DER - */ -define('FILE_X509_FORMAT_DER', 1); -/** - * Save as a SPKAC - * - * Only works on CSRs. Not currently supported. - */ -define('FILE_X509_FORMAT_SPKAC', 2); -/** - * Auto-detect the format - * - * Used only by the load*() functions - */ -define('FILE_X509_FORMAT_AUTO_DETECT', 3); -/**#@-*/ - -/** - * Attribute value disposition. - * If disposition is >= 0, this is the index of the target value. - */ -define('FILE_X509_ATTR_ALL', -1); // All attribute values (array). -define('FILE_X509_ATTR_APPEND', -2); // Add a value. -define('FILE_X509_ATTR_REPLACE', -3); // Clear first, then add a value. - -/** - * Pure-PHP X.509 Parser - * - * @package File_X509 - * @author Jim Wigginton <terrafrost@php.net> - * @access public - */ -class File_X509 -{ - /** - * ASN.1 syntax for X.509 certificates - * - * @var array - * @access private - */ - var $Certificate; - - /**#@+ - * ASN.1 syntax for various extensions - * - * @access private - */ - var $DirectoryString; - var $PKCS9String; - var $AttributeValue; - var $Extensions; - var $KeyUsage; - var $ExtKeyUsageSyntax; - var $BasicConstraints; - var $KeyIdentifier; - var $CRLDistributionPoints; - var $AuthorityKeyIdentifier; - var $CertificatePolicies; - var $AuthorityInfoAccessSyntax; - var $SubjectAltName; - var $SubjectDirectoryAttributes; - var $PrivateKeyUsagePeriod; - var $IssuerAltName; - var $PolicyMappings; - var $NameConstraints; - - var $CPSuri; - var $UserNotice; - - var $netscape_cert_type; - var $netscape_comment; - var $netscape_ca_policy_url; - - var $Name; - var $RelativeDistinguishedName; - var $CRLNumber; - var $CRLReason; - var $IssuingDistributionPoint; - var $InvalidityDate; - var $CertificateIssuer; - var $HoldInstructionCode; - var $SignedPublicKeyAndChallenge; - /**#@-*/ - - /**#@+ - * ASN.1 syntax for various DN attributes - * - * @access private - */ - var $PostalAddress; - /**#@-*/ - - /** - * ASN.1 syntax for Certificate Signing Requests (RFC2986) - * - * @var array - * @access private - */ - var $CertificationRequest; - - /** - * ASN.1 syntax for Certificate Revocation Lists (RFC5280) - * - * @var array - * @access private - */ - var $CertificateList; - - /** - * Distinguished Name - * - * @var array - * @access private - */ - var $dn; - - /** - * Public key - * - * @var string - * @access private - */ - var $publicKey; - - /** - * Private key - * - * @var string - * @access private - */ - var $privateKey; - - /** - * Object identifiers for X.509 certificates - * - * @var array - * @access private - * @link http://en.wikipedia.org/wiki/Object_identifier - */ - var $oids; - - /** - * The certificate authorities - * - * @var array - * @access private - */ - var $CAs; - - /** - * The currently loaded certificate - * - * @var array - * @access private - */ - var $currentCert; - - /** - * The signature subject - * - * There's no guarantee File_X509 is going to re-encode an X.509 cert in the same way it was originally - * encoded so we take save the portion of the original cert that the signature would have made for. - * - * @var string - * @access private - */ - var $signatureSubject; - - /** - * Certificate Start Date - * - * @var string - * @access private - */ - var $startDate; - - /** - * Certificate End Date - * - * @var string - * @access private - */ - var $endDate; - - /** - * Serial Number - * - * @var string - * @access private - */ - var $serialNumber; - - /** - * Key Identifier - * - * See {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.1 RFC5280#section-4.2.1.1} and - * {@link http://tools.ietf.org/html/rfc5280#section-4.2.1.2 RFC5280#section-4.2.1.2}. - * - * @var string - * @access private - */ - var $currentKeyIdentifier; - - /** - * CA Flag - * - * @var bool - * @access private - */ - var $caFlag = false; - - /** - * SPKAC Challenge - * - * @var string - * @access private - */ - var $challenge; - - /** - * Default Constructor. - * - * @return File_X509 - * @access public - */ - function __construct() - { - if (!class_exists('Math_BigInteger')) { - include_once 'Math/BigInteger.php'; - } - - // Explicitly Tagged Module, 1988 Syntax - // http://tools.ietf.org/html/rfc5280#appendix-A.1 - - $this->DirectoryString = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'teletexString' => array('type' => FILE_ASN1_TYPE_TELETEX_STRING), - 'printableString' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING), - 'universalString' => array('type' => FILE_ASN1_TYPE_UNIVERSAL_STRING), - 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING), - 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING) - ) - ); - - $this->PKCS9String = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING), - 'directoryString' => $this->DirectoryString - ) - ); - - $this->AttributeValue = array('type' => FILE_ASN1_TYPE_ANY); - - $AttributeType = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $AttributeTypeAndValue = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => $AttributeType, - 'value'=> $this->AttributeValue - ) - ); - - /* - In practice, RDNs containing multiple name-value pairs (called "multivalued RDNs") are rare, - but they can be useful at times when either there is no unique attribute in the entry or you - want to ensure that the entry's DN contains some useful identifying information. - - - https://www.opends.org/wiki/page/DefinitionRelativeDistinguishedName - */ - $this->RelativeDistinguishedName = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $AttributeTypeAndValue - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.2.4 - $RDNSequence = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - // RDNSequence does not define a min or a max, which means it doesn't have one - 'min' => 0, - 'max' => -1, - 'children' => $this->RelativeDistinguishedName - ); - - $this->Name = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'rdnSequence' => $RDNSequence - ) - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.1.2 - $AlgorithmIdentifier = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'algorithm' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'parameters' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'optional' => true - ) - ) - ); - - /* - A certificate using system MUST reject the certificate if it encounters - a critical extension it does not recognize; however, a non-critical - extension may be ignored if it is not recognized. - - http://tools.ietf.org/html/rfc5280#section-4.2 - */ - $Extension = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'extnId' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'critical' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'optional' => true, - 'default' => false - ), - 'extnValue' => array('type' => FILE_ASN1_TYPE_OCTET_STRING) - ) - ); - - $this->Extensions = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - // technically, it's MAX, but we'll assume anything < 0 is MAX - 'max' => -1, - // if 'children' isn't an array then 'min' and 'max' must be defined - 'children' => $Extension - ); - - $SubjectPublicKeyInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'algorithm' => $AlgorithmIdentifier, - 'subjectPublicKey' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $UniqueIdentifier = array('type' => FILE_ASN1_TYPE_BIT_STRING); - - $Time = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'utcTime' => array('type' => FILE_ASN1_TYPE_UTC_TIME), - 'generalTime' => array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME) - ) - ); - - // http://tools.ietf.org/html/rfc5280#section-4.1.2.5 - $Validity = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'notBefore' => $Time, - 'notAfter' => $Time - ) - ); - - $CertificateSerialNumber = array('type' => FILE_ASN1_TYPE_INTEGER); - - $Version = array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'mapping' => array('v1', 'v2', 'v3') - ); - - // assert($TBSCertificate['children']['signature'] == $Certificate['children']['signatureAlgorithm']) - $TBSCertificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - // technically, default implies optional, but we'll define it as being optional, none-the-less, just to - // reenforce that fact - 'version' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true, - 'default' => 'v1' - ) + $Version, - 'serialNumber' => $CertificateSerialNumber, - 'signature' => $AlgorithmIdentifier, - 'issuer' => $this->Name, - 'validity' => $Validity, - 'subject' => $this->Name, - 'subjectPublicKeyInfo' => $SubjectPublicKeyInfo, - // implicit means that the T in the TLV structure is to be rewritten, regardless of the type - 'issuerUniqueID' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $UniqueIdentifier, - 'subjectUniqueID' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $UniqueIdentifier, - // <http://tools.ietf.org/html/rfc2459#page-74> doesn't use the EXPLICIT keyword but if - // it's not IMPLICIT, it's EXPLICIT - 'extensions' => array( - 'constant' => 3, - 'optional' => true, - 'explicit' => true - ) + $this->Extensions - ) - ); - - $this->Certificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'tbsCertificate' => $TBSCertificate, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $this->KeyUsage = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'digitalSignature', - 'nonRepudiation', - 'keyEncipherment', - 'dataEncipherment', - 'keyAgreement', - 'keyCertSign', - 'cRLSign', - 'encipherOnly', - 'decipherOnly' - ) - ); - - $this->BasicConstraints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'cA' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'optional' => true, - 'default' => false - ), - 'pathLenConstraint' => array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'optional' => true - ) - ) - ); - - $this->KeyIdentifier = array('type' => FILE_ASN1_TYPE_OCTET_STRING); - - $OrganizationalUnitNames = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 4, // ub-organizational-units - 'children' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ); - - $PersonalName = array( - 'type' => FILE_ASN1_TYPE_SET, - 'children' => array( - 'surname' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ), - 'given-name' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ), - 'initials' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ), - 'generation-qualifier' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) - ) - ); - - $NumericUserIdentifier = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING); - - $OrganizationName = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING); - - $PrivateDomainName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $TerminalIdentifier = array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING); - - $NetworkAddress = array('type' => FILE_ASN1_TYPE_NUMERIC_STRING); - - $AdministrationDomainName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or - // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC - 'class' => FILE_ASN1_CLASS_APPLICATION, - 'cast' => 2, - 'children' => array( - 'numeric' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'printable' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $CountryName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - // if class isn't present it's assumed to be FILE_ASN1_CLASS_UNIVERSAL or - // (if constant is present) FILE_ASN1_CLASS_CONTEXT_SPECIFIC - 'class' => FILE_ASN1_CLASS_APPLICATION, - 'cast' => 1, - 'children' => array( - 'x121-dcc-code' => array('type' => FILE_ASN1_TYPE_NUMERIC_STRING), - 'iso-3166-alpha2-code' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $AnotherName = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type-id' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'value' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) - ) - ); - - $ExtensionAttribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'extension-attribute-type' => array( - 'type' => FILE_ASN1_TYPE_PRINTABLE_STRING, - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ), - 'extension-attribute-value' => array( - 'type' => FILE_ASN1_TYPE_ANY, - 'constant' => 1, - 'optional' => true, - 'explicit' => true - ) - ) - ); - - $ExtensionAttributes = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => 256, // ub-extension-attributes - 'children' => $ExtensionAttribute - ); - - $BuiltInDomainDefinedAttribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING), - 'value' => array('type' => FILE_ASN1_TYPE_PRINTABLE_STRING) - ) - ); - - $BuiltInDomainDefinedAttributes = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 4, // ub-domain-defined-attributes - 'children' => $BuiltInDomainDefinedAttribute - ); - - $BuiltInStandardAttributes = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'country-name' => array('optional' => true) + $CountryName, - 'administration-domain-name' => array('optional' => true) + $AdministrationDomainName, - 'network-address' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $NetworkAddress, - 'terminal-identifier' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $TerminalIdentifier, - 'private-domain-name' => array( - 'constant' => 2, - 'optional' => true, - 'explicit' => true - ) + $PrivateDomainName, - 'organization-name' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $OrganizationName, - 'numeric-user-identifier' => array( - 'constant' => 4, - 'optional' => true, - 'implicit' => true - ) + $NumericUserIdentifier, - 'personal-name' => array( - 'constant' => 5, - 'optional' => true, - 'implicit' => true - ) + $PersonalName, - 'organizational-unit-names' => array( - 'constant' => 6, - 'optional' => true, - 'implicit' => true - ) + $OrganizationalUnitNames - ) - ); - - $ORAddress = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'built-in-standard-attributes' => $BuiltInStandardAttributes, - 'built-in-domain-defined-attributes' => array('optional' => true) + $BuiltInDomainDefinedAttributes, - 'extension-attributes' => array('optional' => true) + $ExtensionAttributes - ) - ); - - $EDIPartyName = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'nameAssigner' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $this->DirectoryString, - // partyName is technically required but File_ASN1 doesn't currently support non-optional constants and - // setting it to optional gets the job done in any event. - 'partyName' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $this->DirectoryString - ) - ); - - $GeneralName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'otherName' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $AnotherName, - 'rfc822Name' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ), - 'dNSName' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ), - 'x400Address' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $ORAddress, - 'directoryName' => array( - 'constant' => 4, - 'optional' => true, - 'explicit' => true - ) + $this->Name, - 'ediPartyName' => array( - 'constant' => 5, - 'optional' => true, - 'implicit' => true - ) + $EDIPartyName, - 'uniformResourceIdentifier' => array( - 'type' => FILE_ASN1_TYPE_IA5_STRING, - 'constant' => 6, - 'optional' => true, - 'implicit' => true - ), - 'iPAddress' => array( - 'type' => FILE_ASN1_TYPE_OCTET_STRING, - 'constant' => 7, - 'optional' => true, - 'implicit' => true - ), - 'registeredID' => array( - 'type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER, - 'constant' => 8, - 'optional' => true, - 'implicit' => true - ) - ) - ); - - $GeneralNames = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $GeneralName - ); - - $this->IssuerAltName = $GeneralNames; - - $ReasonFlags = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'unused', - 'keyCompromise', - 'cACompromise', - 'affiliationChanged', - 'superseded', - 'cessationOfOperation', - 'certificateHold', - 'privilegeWithdrawn', - 'aACompromise' - ) - ); - - $DistributionPointName = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'fullName' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames, - 'nameRelativeToCRLIssuer' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $this->RelativeDistinguishedName - ) - ); - - $DistributionPoint = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'distributionPoint' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $DistributionPointName, - 'reasons' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $ReasonFlags, - 'cRLIssuer' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames - ) - ); - - $this->CRLDistributionPoints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $DistributionPoint - ); - - $this->AuthorityKeyIdentifier = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'keyIdentifier' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $this->KeyIdentifier, - 'authorityCertIssuer' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $GeneralNames, - 'authorityCertSerialNumber' => array( - 'constant' => 2, - 'optional' => true, - 'implicit' => true - ) + $CertificateSerialNumber - ) - ); - - $PolicyQualifierId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PolicyQualifierInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'policyQualifierId' => $PolicyQualifierId, - 'qualifier' => array('type' => FILE_ASN1_TYPE_ANY) - ) - ); - - $CertPolicyId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PolicyInformation = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'policyIdentifier' => $CertPolicyId, - 'policyQualifiers' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 0, - 'max' => -1, - 'optional' => true, - 'children' => $PolicyQualifierInfo - ) - ) - ); - - $this->CertificatePolicies = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $PolicyInformation - ); - - $this->PolicyMappings = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'issuerDomainPolicy' => $CertPolicyId, - 'subjectDomainPolicy' => $CertPolicyId - ) - ) - ); - - $KeyPurposeId = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $this->ExtKeyUsageSyntax = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $KeyPurposeId - ); - - $AccessDescription = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'accessMethod' => array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER), - 'accessLocation' => $GeneralName - ) - ); - - $this->AuthorityInfoAccessSyntax = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $AccessDescription - ); - - $this->SubjectAltName = $GeneralNames; - - $this->PrivateKeyUsagePeriod = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'notBefore' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true, - 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME), - 'notAfter' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true, - 'type' => FILE_ASN1_TYPE_GENERALIZED_TIME) - ) - ); - - $BaseDistance = array('type' => FILE_ASN1_TYPE_INTEGER); - - $GeneralSubtree = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'base' => $GeneralName, - 'minimum' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true, - 'default' => new Math_BigInteger(0) - ) + $BaseDistance, - 'maximum' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true, - ) + $BaseDistance - ) - ); - - $GeneralSubtrees = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $GeneralSubtree - ); - - $this->NameConstraints = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'permittedSubtrees' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $GeneralSubtrees, - 'excludedSubtrees' => array( - 'constant' => 1, - 'optional' => true, - 'implicit' => true - ) + $GeneralSubtrees - ) - ); - - $this->CPSuri = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - $DisplayText = array( - 'type' => FILE_ASN1_TYPE_CHOICE, - 'children' => array( - 'ia5String' => array('type' => FILE_ASN1_TYPE_IA5_STRING), - 'visibleString' => array('type' => FILE_ASN1_TYPE_VISIBLE_STRING), - 'bmpString' => array('type' => FILE_ASN1_TYPE_BMP_STRING), - 'utf8String' => array('type' => FILE_ASN1_TYPE_UTF8_STRING) - ) - ); - - $NoticeReference = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'organization' => $DisplayText, - 'noticeNumbers' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => 200, - 'children' => array('type' => FILE_ASN1_TYPE_INTEGER) - ) - ) - ); - - $this->UserNotice = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'noticeRef' => array( - 'optional' => true, - 'implicit' => true - ) + $NoticeReference, - 'explicitText' => array( - 'optional' => true, - 'implicit' => true - ) + $DisplayText - ) - ); - - // mapping is from <http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html> - $this->netscape_cert_type = array( - 'type' => FILE_ASN1_TYPE_BIT_STRING, - 'mapping' => array( - 'SSLClient', - 'SSLServer', - 'Email', - 'ObjectSigning', - 'Reserved', - 'SSLCA', - 'EmailCA', - 'ObjectSigningCA' - ) - ); - - $this->netscape_comment = array('type' => FILE_ASN1_TYPE_IA5_STRING); - $this->netscape_ca_policy_url = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - // attribute is used in RFC2986 but we're using the RFC5280 definition - - $Attribute = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'type' => $AttributeType, - 'value'=> array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $this->AttributeValue - ) - ) - ); - - $this->SubjectDirectoryAttributes = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'min' => 1, - 'max' => -1, - 'children' => $Attribute - ); - - // adapted from <http://tools.ietf.org/html/rfc2986> - - $Attributes = array( - 'type' => FILE_ASN1_TYPE_SET, - 'min' => 1, - 'max' => -1, - 'children' => $Attribute - ); - - $CertificationRequestInfo = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'version' => array( - 'type' => FILE_ASN1_TYPE_INTEGER, - 'mapping' => array('v1') - ), - 'subject' => $this->Name, - 'subjectPKInfo' => $SubjectPublicKeyInfo, - 'attributes' => array( - 'constant' => 0, - 'optional' => true, - 'implicit' => true - ) + $Attributes, - ) - ); - - $this->CertificationRequest = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'certificationRequestInfo' => $CertificationRequestInfo, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $RevokedCertificate = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'userCertificate' => $CertificateSerialNumber, - 'revocationDate' => $Time, - 'crlEntryExtensions' => array( - 'optional' => true - ) + $this->Extensions - ) - ); - - $TBSCertList = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'version' => array( - 'optional' => true, - 'default' => 'v1' - ) + $Version, - 'signature' => $AlgorithmIdentifier, - 'issuer' => $this->Name, - 'thisUpdate' => $Time, - 'nextUpdate' => array( - 'optional' => true - ) + $Time, - 'revokedCertificates' => array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'optional' => true, - 'min' => 0, - 'max' => -1, - 'children' => $RevokedCertificate - ), - 'crlExtensions' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $this->Extensions - ) - ); - - $this->CertificateList = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'tbsCertList' => $TBSCertList, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $this->CRLNumber = array('type' => FILE_ASN1_TYPE_INTEGER); - - $this->CRLReason = array('type' => FILE_ASN1_TYPE_ENUMERATED, - 'mapping' => array( - 'unspecified', - 'keyCompromise', - 'cACompromise', - 'affiliationChanged', - 'superseded', - 'cessationOfOperation', - 'certificateHold', - // Value 7 is not used. - 8 => 'removeFromCRL', - 'privilegeWithdrawn', - 'aACompromise' - ) - ); - - $this->IssuingDistributionPoint = array('type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'distributionPoint' => array( - 'constant' => 0, - 'optional' => true, - 'explicit' => true - ) + $DistributionPointName, - 'onlyContainsUserCerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 1, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlyContainsCACerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 2, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlySomeReasons' => array( - 'constant' => 3, - 'optional' => true, - 'implicit' => true - ) + $ReasonFlags, - 'indirectCRL' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 4, - 'optional' => true, - 'default' => false, - 'implicit' => true - ), - 'onlyContainsAttributeCerts' => array( - 'type' => FILE_ASN1_TYPE_BOOLEAN, - 'constant' => 5, - 'optional' => true, - 'default' => false, - 'implicit' => true - ) - ) - ); - - $this->InvalidityDate = array('type' => FILE_ASN1_TYPE_GENERALIZED_TIME); - - $this->CertificateIssuer = $GeneralNames; - - $this->HoldInstructionCode = array('type' => FILE_ASN1_TYPE_OBJECT_IDENTIFIER); - - $PublicKeyAndChallenge = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'spki' => $SubjectPublicKeyInfo, - 'challenge' => array('type' => FILE_ASN1_TYPE_IA5_STRING) - ) - ); - - $this->SignedPublicKeyAndChallenge = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'children' => array( - 'publicKeyAndChallenge' => $PublicKeyAndChallenge, - 'signatureAlgorithm' => $AlgorithmIdentifier, - 'signature' => array('type' => FILE_ASN1_TYPE_BIT_STRING) - ) - ); - - $this->PostalAddress = array( - 'type' => FILE_ASN1_TYPE_SEQUENCE, - 'optional' => true, - 'min' => 1, - 'max' => -1, - 'children' => $this->DirectoryString - ); - - // OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2 - $this->oids = array( - '1.3.6.1.5.5.7' => 'id-pkix', - '1.3.6.1.5.5.7.1' => 'id-pe', - '1.3.6.1.5.5.7.2' => 'id-qt', - '1.3.6.1.5.5.7.3' => 'id-kp', - '1.3.6.1.5.5.7.48' => 'id-ad', - '1.3.6.1.5.5.7.2.1' => 'id-qt-cps', - '1.3.6.1.5.5.7.2.2' => 'id-qt-unotice', - '1.3.6.1.5.5.7.48.1' =>'id-ad-ocsp', - '1.3.6.1.5.5.7.48.2' => 'id-ad-caIssuers', - '1.3.6.1.5.5.7.48.3' => 'id-ad-timeStamping', - '1.3.6.1.5.5.7.48.5' => 'id-ad-caRepository', - '2.5.4' => 'id-at', - '2.5.4.41' => 'id-at-name', - '2.5.4.4' => 'id-at-surname', - '2.5.4.42' => 'id-at-givenName', - '2.5.4.43' => 'id-at-initials', - '2.5.4.44' => 'id-at-generationQualifier', - '2.5.4.3' => 'id-at-commonName', - '2.5.4.7' => 'id-at-localityName', - '2.5.4.8' => 'id-at-stateOrProvinceName', - '2.5.4.10' => 'id-at-organizationName', - '2.5.4.11' => 'id-at-organizationalUnitName', - '2.5.4.12' => 'id-at-title', - '2.5.4.13' => 'id-at-description', - '2.5.4.46' => 'id-at-dnQualifier', - '2.5.4.6' => 'id-at-countryName', - '2.5.4.5' => 'id-at-serialNumber', - '2.5.4.65' => 'id-at-pseudonym', - '2.5.4.17' => 'id-at-postalCode', - '2.5.4.9' => 'id-at-streetAddress', - '2.5.4.45' => 'id-at-uniqueIdentifier', - '2.5.4.72' => 'id-at-role', - '2.5.4.16' => 'id-at-postalAddress', - - '0.9.2342.19200300.100.1.25' => 'id-domainComponent', - '1.2.840.113549.1.9' => 'pkcs-9', - '1.2.840.113549.1.9.1' => 'pkcs-9-at-emailAddress', - '2.5.29' => 'id-ce', - '2.5.29.35' => 'id-ce-authorityKeyIdentifier', - '2.5.29.14' => 'id-ce-subjectKeyIdentifier', - '2.5.29.15' => 'id-ce-keyUsage', - '2.5.29.16' => 'id-ce-privateKeyUsagePeriod', - '2.5.29.32' => 'id-ce-certificatePolicies', - '2.5.29.32.0' => 'anyPolicy', - - '2.5.29.33' => 'id-ce-policyMappings', - '2.5.29.17' => 'id-ce-subjectAltName', - '2.5.29.18' => 'id-ce-issuerAltName', - '2.5.29.9' => 'id-ce-subjectDirectoryAttributes', - '2.5.29.19' => 'id-ce-basicConstraints', - '2.5.29.30' => 'id-ce-nameConstraints', - '2.5.29.36' => 'id-ce-policyConstraints', - '2.5.29.31' => 'id-ce-cRLDistributionPoints', - '2.5.29.37' => 'id-ce-extKeyUsage', - '2.5.29.37.0' => 'anyExtendedKeyUsage', - '1.3.6.1.5.5.7.3.1' => 'id-kp-serverAuth', - '1.3.6.1.5.5.7.3.2' => 'id-kp-clientAuth', - '1.3.6.1.5.5.7.3.3' => 'id-kp-codeSigning', - '1.3.6.1.5.5.7.3.4' => 'id-kp-emailProtection', - '1.3.6.1.5.5.7.3.8' => 'id-kp-timeStamping', - '1.3.6.1.5.5.7.3.9' => 'id-kp-OCSPSigning', - '2.5.29.54' => 'id-ce-inhibitAnyPolicy', - '2.5.29.46' => 'id-ce-freshestCRL', - '1.3.6.1.5.5.7.1.1' => 'id-pe-authorityInfoAccess', - '1.3.6.1.5.5.7.1.11' => 'id-pe-subjectInfoAccess', - '2.5.29.20' => 'id-ce-cRLNumber', - '2.5.29.28' => 'id-ce-issuingDistributionPoint', - '2.5.29.27' => 'id-ce-deltaCRLIndicator', - '2.5.29.21' => 'id-ce-cRLReasons', - '2.5.29.29' => 'id-ce-certificateIssuer', - '2.5.29.23' => 'id-ce-holdInstructionCode', - '1.2.840.10040.2' => 'holdInstruction', - '1.2.840.10040.2.1' => 'id-holdinstruction-none', - '1.2.840.10040.2.2' => 'id-holdinstruction-callissuer', - '1.2.840.10040.2.3' => 'id-holdinstruction-reject', - '2.5.29.24' => 'id-ce-invalidityDate', - - '1.2.840.113549.2.2' => 'md2', - '1.2.840.113549.2.5' => 'md5', - '1.3.14.3.2.26' => 'id-sha1', - '1.2.840.10040.4.1' => 'id-dsa', - '1.2.840.10040.4.3' => 'id-dsa-with-sha1', - '1.2.840.113549.1.1' => 'pkcs-1', - '1.2.840.113549.1.1.1' => 'rsaEncryption', - '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', - '1.2.840.113549.1.1.4' => 'md5WithRSAEncryption', - '1.2.840.113549.1.1.5' => 'sha1WithRSAEncryption', - '1.2.840.10046.2.1' => 'dhpublicnumber', - '2.16.840.1.101.2.1.1.22' => 'id-keyExchangeAlgorithm', - '1.2.840.10045' => 'ansi-X9-62', - '1.2.840.10045.4' => 'id-ecSigType', - '1.2.840.10045.4.1' => 'ecdsa-with-SHA1', - '1.2.840.10045.1' => 'id-fieldType', - '1.2.840.10045.1.1' => 'prime-field', - '1.2.840.10045.1.2' => 'characteristic-two-field', - '1.2.840.10045.1.2.3' => 'id-characteristic-two-basis', - '1.2.840.10045.1.2.3.1' => 'gnBasis', - '1.2.840.10045.1.2.3.2' => 'tpBasis', - '1.2.840.10045.1.2.3.3' => 'ppBasis', - '1.2.840.10045.2' => 'id-publicKeyType', - '1.2.840.10045.2.1' => 'id-ecPublicKey', - '1.2.840.10045.3' => 'ellipticCurve', - '1.2.840.10045.3.0' => 'c-TwoCurve', - '1.2.840.10045.3.0.1' => 'c2pnb163v1', - '1.2.840.10045.3.0.2' => 'c2pnb163v2', - '1.2.840.10045.3.0.3' => 'c2pnb163v3', - '1.2.840.10045.3.0.4' => 'c2pnb176w1', - '1.2.840.10045.3.0.5' => 'c2pnb191v1', - '1.2.840.10045.3.0.6' => 'c2pnb191v2', - '1.2.840.10045.3.0.7' => 'c2pnb191v3', - '1.2.840.10045.3.0.8' => 'c2pnb191v4', - '1.2.840.10045.3.0.9' => 'c2pnb191v5', - '1.2.840.10045.3.0.10' => 'c2pnb208w1', - '1.2.840.10045.3.0.11' => 'c2pnb239v1', - '1.2.840.10045.3.0.12' => 'c2pnb239v2', - '1.2.840.10045.3.0.13' => 'c2pnb239v3', - '1.2.840.10045.3.0.14' => 'c2pnb239v4', - '1.2.840.10045.3.0.15' => 'c2pnb239v5', - '1.2.840.10045.3.0.16' => 'c2pnb272w1', - '1.2.840.10045.3.0.17' => 'c2pnb304w1', - '1.2.840.10045.3.0.18' => 'c2pnb359v1', - '1.2.840.10045.3.0.19' => 'c2pnb368w1', - '1.2.840.10045.3.0.20' => 'c2pnb431r1', - '1.2.840.10045.3.1' => 'primeCurve', - '1.2.840.10045.3.1.1' => 'prime192v1', - '1.2.840.10045.3.1.2' => 'prime192v2', - '1.2.840.10045.3.1.3' => 'prime192v3', - '1.2.840.10045.3.1.4' => 'prime239v1', - '1.2.840.10045.3.1.5' => 'prime239v2', - '1.2.840.10045.3.1.6' => 'prime239v3', - '1.2.840.10045.3.1.7' => 'prime256v1', - '1.2.840.113549.1.1.7' => 'id-RSAES-OAEP', - '1.2.840.113549.1.1.9' => 'id-pSpecified', - '1.2.840.113549.1.1.10' => 'id-RSASSA-PSS', - '1.2.840.113549.1.1.8' => 'id-mgf1', - '1.2.840.113549.1.1.14' => 'sha224WithRSAEncryption', - '1.2.840.113549.1.1.11' => 'sha256WithRSAEncryption', - '1.2.840.113549.1.1.12' => 'sha384WithRSAEncryption', - '1.2.840.113549.1.1.13' => 'sha512WithRSAEncryption', - '2.16.840.1.101.3.4.2.4' => 'id-sha224', - '2.16.840.1.101.3.4.2.1' => 'id-sha256', - '2.16.840.1.101.3.4.2.2' => 'id-sha384', - '2.16.840.1.101.3.4.2.3' => 'id-sha512', - '1.2.643.2.2.4' => 'id-GostR3411-94-with-GostR3410-94', - '1.2.643.2.2.3' => 'id-GostR3411-94-with-GostR3410-2001', - '1.2.643.2.2.20' => 'id-GostR3410-2001', - '1.2.643.2.2.19' => 'id-GostR3410-94', - // Netscape Object Identifiers from "Netscape Certificate Extensions" - '2.16.840.1.113730' => 'netscape', - '2.16.840.1.113730.1' => 'netscape-cert-extension', - '2.16.840.1.113730.1.1' => 'netscape-cert-type', - '2.16.840.1.113730.1.13' => 'netscape-comment', - '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url', - // the following are X.509 extensions not supported by phpseclib - '1.3.6.1.5.5.7.1.12' => 'id-pe-logotype', - '1.2.840.113533.7.65.0' => 'entrustVersInfo', - '2.16.840.1.113733.1.6.9' => 'verisignPrivate', - // for Certificate Signing Requests - // see http://tools.ietf.org/html/rfc2985 - '1.2.840.113549.1.9.2' => 'pkcs-9-at-unstructuredName', // PKCS #9 unstructured name - '1.2.840.113549.1.9.7' => 'pkcs-9-at-challengePassword', // Challenge password for certificate revocations - '1.2.840.113549.1.9.14' => 'pkcs-9-at-extensionRequest' // Certificate extension request - ); - } - - /** - * PHP4 compatible Default Constructor. - * - * @see self::__construct() - * @access public - */ - function File_X509() - { - $this->__construct(); - } - - /** - * Load X.509 certificate - * - * Returns an associative array describing the X.509 cert or a false if the cert failed to load - * - * @param string $cert - * @param int $mode - * @access public - * @return mixed - */ - function loadX509($cert, $mode = FILE_X509_FORMAT_AUTO_DETECT) - { - if (is_array($cert) && isset($cert['tbsCertificate'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - $this->dn = $cert['tbsCertificate']['subject']; - if (!isset($this->dn)) { - return false; - } - $this->currentCert = $cert; - - $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; - - unset($this->signatureSubject); - - return $cert; - } - - $asn1 = new File_ASN1(); - - if ($mode != FILE_X509_FORMAT_DER) { - $newcert = $this->_extractBER($cert); - if ($mode == FILE_X509_FORMAT_PEM && $cert == $newcert) { - return false; - } - $cert = $newcert; - } - - if ($cert === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($cert); - - if (!empty($decoded)) { - $x509 = $asn1->asn1map($decoded[0], $this->Certificate); - } - if (!isset($x509) || $x509 === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) { - $this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1); - } - $this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1); - $this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1); - - $key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']; - $key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key); - - $this->currentCert = $x509; - $this->dn = $x509['tbsCertificate']['subject']; - - $currentKeyIdentifier = $this->getExtension('id-ce-subjectKeyIdentifier'); - $this->currentKeyIdentifier = is_string($currentKeyIdentifier) ? $currentKeyIdentifier : null; - - return $x509; - } - - /** - * Save X.509 certificate - * - * @param array $cert - * @param int $format optional - * @access public - * @return string - */ - function saveX509($cert, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($cert) || !isset($cert['tbsCertificate'])) { - return false; - } - - switch (true) { - // "case !$a: case !$b: break; default: whatever();" is the same thing as "if ($a && $b) whatever()" - case !($algorithm = $this->_subArray($cert, 'tbsCertificate/subjectPublicKeyInfo/algorithm/algorithm')): - case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']): - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); - /* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier." - -- https://tools.ietf.org/html/rfc3279#section-2.3.1 - - given that and the fact that RSA keys appear ot be the only key type for which the parameters field can be blank, - it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever. - */ - $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null; - // https://tools.ietf.org/html/rfc3279#section-2.2.1 - $cert['signatureAlgorithm']['parameters'] = null; - $cert['tbsCertificate']['signature']['parameters'] = null; - } - } - - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - - $filters = array(); - $type_utf8_string = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['tbsCertificate']['signature']['parameters'] = $type_utf8_string; - $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $type_utf8_string; - $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $type_utf8_string; - $filters['signatureAlgorithm']['parameters'] = $type_utf8_string; - $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $type_utf8_string; - //$filters['policyQualifiers']['qualifier'] = $type_utf8_string; - $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $type_utf8_string; - $filters['directoryName']['rdnSequence']['value'] = $type_utf8_string; - - /* in the case of policyQualifiers/qualifier, the type has to be FILE_ASN1_TYPE_IA5_STRING. - FILE_ASN1_TYPE_PRINTABLE_STRING will cause OpenSSL's X.509 parser to spit out random - characters. - */ - $filters['policyQualifiers']['qualifier'] - = array('type' => FILE_ASN1_TYPE_IA5_STRING); - - $asn1->loadFilters($filters); - - $this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1); - $this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1); - $this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1); - - $cert = $asn1->encodeDER($cert, $this->Certificate); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $cert; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----'; - } - } - - /** - * Map extension values from octet string to extension-specific internal - * format. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapInExtensions(&$root, $path, $asn1) - { - $extensions = &$this->_subArrayUnchecked($root, $path); - - if ($extensions) { - for ($i = 0; $i < count($extensions); $i++) { - $id = $extensions[$i]['extnId']; - $value = &$extensions[$i]['extnValue']; - $value = base64_decode($value); - $decoded = $asn1->decodeBER($value); - /* [extnValue] contains the DER encoding of an ASN.1 value - corresponding to the extension type identified by extnID */ - $map = $this->_getMapping($id); - if (!is_bool($map)) { - $mapped = $asn1->asn1map($decoded[0], $map, array('iPAddress' => array($this, '_decodeIP'))); - $value = $mapped === false ? $decoded[0] : $mapped; - - if ($id == 'id-ce-certificatePolicies') { - for ($j = 0; $j < count($value); $j++) { - if (!isset($value[$j]['policyQualifiers'])) { - continue; - } - for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { - $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; - $map = $this->_getMapping($subid); - $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; - if ($map !== false) { - $decoded = $asn1->decodeBER($subvalue); - $mapped = $asn1->asn1map($decoded[0], $map); - $subvalue = $mapped === false ? $decoded[0] : $mapped; - } - } - } - } - } else { - $value = base64_encode($value); - } - } - } - } - - /** - * Map extension values from extension-specific internal format to - * octet string. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapOutExtensions(&$root, $path, $asn1) - { - $extensions = &$this->_subArray($root, $path); - - if (is_array($extensions)) { - $size = count($extensions); - for ($i = 0; $i < $size; $i++) { - if (is_object($extensions[$i]) && strtolower(get_class($extensions[$i])) == 'file_asn1_element') { - continue; - } - - $id = $extensions[$i]['extnId']; - $value = &$extensions[$i]['extnValue']; - - switch ($id) { - case 'id-ce-certificatePolicies': - for ($j = 0; $j < count($value); $j++) { - if (!isset($value[$j]['policyQualifiers'])) { - continue; - } - for ($k = 0; $k < count($value[$j]['policyQualifiers']); $k++) { - $subid = $value[$j]['policyQualifiers'][$k]['policyQualifierId']; - $map = $this->_getMapping($subid); - $subvalue = &$value[$j]['policyQualifiers'][$k]['qualifier']; - if ($map !== false) { - // by default File_ASN1 will try to render qualifier as a FILE_ASN1_TYPE_IA5_STRING since it's - // actual type is FILE_ASN1_TYPE_ANY - $subvalue = new File_ASN1_Element($asn1->encodeDER($subvalue, $map)); - } - } - } - break; - case 'id-ce-authorityKeyIdentifier': // use 00 as the serial number instead of an empty string - if (isset($value['authorityCertSerialNumber'])) { - if ($value['authorityCertSerialNumber']->toBytes() == '') { - $temp = chr((FILE_ASN1_CLASS_CONTEXT_SPECIFIC << 6) | 2) . "\1\0"; - $value['authorityCertSerialNumber'] = new File_ASN1_Element($temp); - } - } - } - - /* [extnValue] contains the DER encoding of an ASN.1 value - corresponding to the extension type identified by extnID */ - $map = $this->_getMapping($id); - if (is_bool($map)) { - if (!$map) { - user_error($id . ' is not a currently supported extension'); - unset($extensions[$i]); - } - } else { - $temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP'))); - $value = base64_encode($temp); - } - } - } - } - - /** - * Map attribute values from ANY type to attribute-specific internal - * format. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapInAttributes(&$root, $path, $asn1) - { - $attributes = &$this->_subArray($root, $path); - - if (is_array($attributes)) { - for ($i = 0; $i < count($attributes); $i++) { - $id = $attributes[$i]['type']; - /* $value contains the DER encoding of an ASN.1 value - corresponding to the attribute type identified by type */ - $map = $this->_getMapping($id); - if (is_array($attributes[$i]['value'])) { - $values = &$attributes[$i]['value']; - for ($j = 0; $j < count($values); $j++) { - $value = $asn1->encodeDER($values[$j], $this->AttributeValue); - $decoded = $asn1->decodeBER($value); - if (!is_bool($map)) { - $mapped = $asn1->asn1map($decoded[0], $map); - if ($mapped !== false) { - $values[$j] = $mapped; - } - if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) { - $this->_mapInExtensions($values, $j, $asn1); - } - } elseif ($map) { - $values[$j] = base64_encode($value); - } - } - } - } - } - } - - /** - * Map attribute values from attribute-specific internal format to - * ANY type. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapOutAttributes(&$root, $path, $asn1) - { - $attributes = &$this->_subArray($root, $path); - - if (is_array($attributes)) { - $size = count($attributes); - for ($i = 0; $i < $size; $i++) { - /* [value] contains the DER encoding of an ASN.1 value - corresponding to the attribute type identified by type */ - $id = $attributes[$i]['type']; - $map = $this->_getMapping($id); - if ($map === false) { - user_error($id . ' is not a currently supported attribute', E_USER_NOTICE); - unset($attributes[$i]); - } elseif (is_array($attributes[$i]['value'])) { - $values = &$attributes[$i]['value']; - for ($j = 0; $j < count($values); $j++) { - switch ($id) { - case 'pkcs-9-at-extensionRequest': - $this->_mapOutExtensions($values, $j, $asn1); - break; - } - - if (!is_bool($map)) { - $temp = $asn1->encodeDER($values[$j], $map); - $decoded = $asn1->decodeBER($temp); - $values[$j] = $asn1->asn1map($decoded[0], $this->AttributeValue); - } - } - } - } - } - } - - /** - * Map DN values from ANY type to DN-specific internal - * format. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapInDNs(&$root, $path, $asn1) - { - $dns = &$this->_subArray($root, $path); - - if (is_array($dns)) { - for ($i = 0; $i < count($dns); $i++) { - for ($j = 0; $j < count($dns[$i]); $j++) { - $type = $dns[$i][$j]['type']; - $value = &$dns[$i][$j]['value']; - if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') { - $map = $this->_getMapping($type); - if (!is_bool($map)) { - $decoded = $asn1->decodeBER($value); - $value = $asn1->asn1map($decoded[0], $map); - } - } - } - } - } - } - - /** - * Map DN values from DN-specific internal format to - * ANY type. - * - * @param array ref $root - * @param string $path - * @param object $asn1 - * @access private - */ - function _mapOutDNs(&$root, $path, $asn1) - { - $dns = &$this->_subArray($root, $path); - - if (is_array($dns)) { - $size = count($dns); - for ($i = 0; $i < $size; $i++) { - for ($j = 0; $j < count($dns[$i]); $j++) { - $type = $dns[$i][$j]['type']; - $value = &$dns[$i][$j]['value']; - if (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') { - continue; - } - - $map = $this->_getMapping($type); - if (!is_bool($map)) { - $value = new File_ASN1_Element($asn1->encodeDER($value, $map)); - } - } - } - } - } - - /** - * Associate an extension ID to an extension mapping - * - * @param string $extnId - * @access private - * @return mixed - */ - function _getMapping($extnId) - { - if (!is_string($extnId)) { // eg. if it's a File_ASN1_Element object - return true; - } - - switch ($extnId) { - case 'id-ce-keyUsage': - return $this->KeyUsage; - case 'id-ce-basicConstraints': - return $this->BasicConstraints; - case 'id-ce-subjectKeyIdentifier': - return $this->KeyIdentifier; - case 'id-ce-cRLDistributionPoints': - return $this->CRLDistributionPoints; - case 'id-ce-authorityKeyIdentifier': - return $this->AuthorityKeyIdentifier; - case 'id-ce-certificatePolicies': - return $this->CertificatePolicies; - case 'id-ce-extKeyUsage': - return $this->ExtKeyUsageSyntax; - case 'id-pe-authorityInfoAccess': - return $this->AuthorityInfoAccessSyntax; - case 'id-ce-subjectAltName': - return $this->SubjectAltName; - case 'id-ce-subjectDirectoryAttributes': - return $this->SubjectDirectoryAttributes; - case 'id-ce-privateKeyUsagePeriod': - return $this->PrivateKeyUsagePeriod; - case 'id-ce-issuerAltName': - return $this->IssuerAltName; - case 'id-ce-policyMappings': - return $this->PolicyMappings; - case 'id-ce-nameConstraints': - return $this->NameConstraints; - - case 'netscape-cert-type': - return $this->netscape_cert_type; - case 'netscape-comment': - return $this->netscape_comment; - case 'netscape-ca-policy-url': - return $this->netscape_ca_policy_url; - - // since id-qt-cps isn't a constructed type it will have already been decoded as a string by the time it gets - // back around to asn1map() and we don't want it decoded again. - //case 'id-qt-cps': - // return $this->CPSuri; - case 'id-qt-unotice': - return $this->UserNotice; - - // the following OIDs are unsupported but we don't want them to give notices when calling saveX509(). - case 'id-pe-logotype': // http://www.ietf.org/rfc/rfc3709.txt - case 'entrustVersInfo': - // http://support.microsoft.com/kb/287547 - case '1.3.6.1.4.1.311.20.2': // szOID_ENROLL_CERTTYPE_EXTENSION - case '1.3.6.1.4.1.311.21.1': // szOID_CERTSRV_CA_VERSION - // "SET Secure Electronic Transaction Specification" - // http://www.maithean.com/docs/set_bk3.pdf - case '2.23.42.7.0': // id-set-hashedRootKey - return true; - - // CSR attributes - case 'pkcs-9-at-unstructuredName': - return $this->PKCS9String; - case 'pkcs-9-at-challengePassword': - return $this->DirectoryString; - case 'pkcs-9-at-extensionRequest': - return $this->Extensions; - - // CRL extensions. - case 'id-ce-cRLNumber': - return $this->CRLNumber; - case 'id-ce-deltaCRLIndicator': - return $this->CRLNumber; - case 'id-ce-issuingDistributionPoint': - return $this->IssuingDistributionPoint; - case 'id-ce-freshestCRL': - return $this->CRLDistributionPoints; - case 'id-ce-cRLReasons': - return $this->CRLReason; - case 'id-ce-invalidityDate': - return $this->InvalidityDate; - case 'id-ce-certificateIssuer': - return $this->CertificateIssuer; - case 'id-ce-holdInstructionCode': - return $this->HoldInstructionCode; - case 'id-at-postalAddress': - return $this->PostalAddress; - } - - return false; - } - - /** - * Load an X.509 certificate as a certificate authority - * - * @param string $cert - * @access public - * @return bool - */ - function loadCA($cert) - { - $olddn = $this->dn; - $oldcert = $this->currentCert; - $oldsigsubj = $this->signatureSubject; - $oldkeyid = $this->currentKeyIdentifier; - - $cert = $this->loadX509($cert); - if (!$cert) { - $this->dn = $olddn; - $this->currentCert = $oldcert; - $this->signatureSubject = $oldsigsubj; - $this->currentKeyIdentifier = $oldkeyid; - - return false; - } - - /* From RFC5280 "PKIX Certificate and CRL Profile": - - If the keyUsage extension is present, then the subject public key - MUST NOT be used to verify signatures on certificates or CRLs unless - the corresponding keyCertSign or cRLSign bit is set. */ - //$keyUsage = $this->getExtension('id-ce-keyUsage'); - //if ($keyUsage && !in_array('keyCertSign', $keyUsage)) { - // return false; - //} - - /* From RFC5280 "PKIX Certificate and CRL Profile": - - The cA boolean indicates whether the certified public key may be used - to verify certificate signatures. If the cA boolean is not asserted, - then the keyCertSign bit in the key usage extension MUST NOT be - asserted. If the basic constraints extension is not present in a - version 3 certificate, or the extension is present but the cA boolean - is not asserted, then the certified public key MUST NOT be used to - verify certificate signatures. */ - //$basicConstraints = $this->getExtension('id-ce-basicConstraints'); - //if (!$basicConstraints || !$basicConstraints['cA']) { - // return false; - //} - - $this->CAs[] = $cert; - - $this->dn = $olddn; - $this->currentCert = $oldcert; - $this->signatureSubject = $oldsigsubj; - - return true; - } - - /** - * Validate an X.509 certificate against a URL - * - * From RFC2818 "HTTP over TLS": - * - * Matching is performed using the matching rules specified by - * [RFC2459]. If more than one identity of a given type is present in - * the certificate (e.g., more than one dNSName name, a match in any one - * of the set is considered acceptable.) Names may contain the wildcard - * character * which is considered to match any single domain name - * component or component fragment. E.g., *.a.com matches foo.a.com but - * not bar.foo.a.com. f*.com matches foo.com but not bar.com. - * - * @param string $url - * @access public - * @return bool - */ - function validateURL($url) - { - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - - $components = parse_url($url); - if (!isset($components['host'])) { - return false; - } - - if ($names = $this->getExtension('id-ce-subjectAltName')) { - foreach ($names as $key => $value) { - $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value); - switch ($key) { - case 'dNSName': - /* From RFC2818 "HTTP over TLS": - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - Certification Authorities are encouraged to use the dNSName instead. */ - if (preg_match('#^' . $value . '$#', $components['host'])) { - return true; - } - break; - case 'iPAddress': - /* From RFC2818 "HTTP over TLS": - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. */ - if (preg_match('#(?:\d{1-3}\.){4}#', $components['host'] . '.') && preg_match('#^' . $value . '$#', $components['host'])) { - return true; - } - } - } - return false; - } - - if ($value = $this->getDNProp('id-at-commonName')) { - $value = str_replace(array('.', '*'), array('\.', '[^.]*'), $value[0]); - return preg_match('#^' . $value . '$#', $components['host']); - } - - return false; - } - - /** - * Validate a date - * - * If $date isn't defined it is assumed to be the current date. - * - * @param int $date optional - * @access public - */ - function validateDate($date = null) - { - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - - if (!isset($date)) { - $date = time(); - } - - $notBefore = $this->currentCert['tbsCertificate']['validity']['notBefore']; - $notBefore = isset($notBefore['generalTime']) ? $notBefore['generalTime'] : $notBefore['utcTime']; - - $notAfter = $this->currentCert['tbsCertificate']['validity']['notAfter']; - $notAfter = isset($notAfter['generalTime']) ? $notAfter['generalTime'] : $notAfter['utcTime']; - - switch (true) { - case $date < @strtotime($notBefore): - case $date > @strtotime($notAfter): - return false; - } - - return true; - } - - /** - * Validate a signature - * - * Works on X.509 certs, CSR's and CRL's. - * Returns true if the signature is verified, false if it is not correct or null on error - * - * By default returns false for self-signed certs. Call validateSignature(false) to make this support - * self-signed. - * - * The behavior of this function is inspired by {@link http://php.net/openssl-verify openssl_verify}. - * - * @param bool $caonly optional - * @access public - * @return mixed - */ - function validateSignature($caonly = true) - { - if (!is_array($this->currentCert) || !isset($this->signatureSubject)) { - return null; - } - - /* TODO: - "emailAddress attribute values are not case-sensitive (e.g., "subscriber@example.com" is the same as "SUBSCRIBER@EXAMPLE.COM")." - -- http://tools.ietf.org/html/rfc5280#section-4.1.2.6 - - implement pathLenConstraint in the id-ce-basicConstraints extension */ - - switch (true) { - case isset($this->currentCert['tbsCertificate']): - // self-signed cert - switch (true) { - case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']: - case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(FILE_X509_DN_STRING) === $this->getDN(FILE_X509_DN_STRING): - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier'); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $this->currentCert; // working cert - } - } - - if (!empty($this->CAs)) { - for ($i = 0; $i < count($this->CAs); $i++) { - // even if the cert is a self-signed one we still want to see if it's a CA; - // if not, we'll conditionally return an error - $ca = $this->CAs[$i]; - switch (true) { - case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']: - case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']): - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $ca; // working cert - break 3; - } - } - } - if (count($this->CAs) == $i && $caonly) { - return false; - } - } elseif (!isset($signingCert) || $caonly) { - return false; - } - return $this->_validateSignature( - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['certificationRequestInfo']): - return $this->_validateSignature( - $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'], - $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['publicKeyAndChallenge']): - return $this->_validateSignature( - $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'], - $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - case isset($this->currentCert['tbsCertList']): - if (!empty($this->CAs)) { - for ($i = 0; $i < count($this->CAs); $i++) { - $ca = $this->CAs[$i]; - switch (true) { - case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']: - case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(FILE_X509_DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(FILE_X509_DN_STRING, $ca['tbsCertificate']['subject']): - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier'); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - $signingCert = $ca; // working cert - break 3; - } - } - } - } - if (!isset($signingCert)) { - return false; - } - return $this->_validateSignature( - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], - $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], - $this->currentCert['signatureAlgorithm']['algorithm'], - substr(base64_decode($this->currentCert['signature']), 1), - $this->signatureSubject - ); - default: - return false; - } - } - - /** - * Validates a signature - * - * Returns true if the signature is verified, false if it is not correct or null on error - * - * @param string $publicKeyAlgorithm - * @param string $publicKey - * @param string $signatureAlgorithm - * @param string $signature - * @param string $signatureSubject - * @access private - * @return int - */ - function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject) - { - switch ($publicKeyAlgorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $rsa = new Crypt_RSA(); - $rsa->loadKey($publicKey); - - switch ($signatureAlgorithm) { - case 'md2WithRSAEncryption': - case 'md5WithRSAEncryption': - case 'sha1WithRSAEncryption': - case 'sha224WithRSAEncryption': - case 'sha256WithRSAEncryption': - case 'sha384WithRSAEncryption': - case 'sha512WithRSAEncryption': - $rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - if (!@$rsa->verify($signatureSubject, $signature)) { - return false; - } - break; - default: - return null; - } - break; - default: - return null; - } - - return true; - } - - /** - * Reformat public keys - * - * Reformats a public key to a format supported by phpseclib (if applicable) - * - * @param string $algorithm - * @param string $key - * @access private - * @return string - */ - function _reformatKey($algorithm, $key) - { - switch ($algorithm) { - case 'rsaEncryption': - return - "-----BEGIN RSA PUBLIC KEY-----\r\n" . - // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits - // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox - // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do. - chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) . - '-----END RSA PUBLIC KEY-----'; - default: - return $key; - } - } - - /** - * Decodes an IP address - * - * Takes in a base64 encoded "blob" and returns a human readable IP address - * - * @param string $ip - * @access private - * @return string - */ - function _decodeIP($ip) - { - $ip = base64_decode($ip); - list(, $ip) = unpack('N', $ip); - return long2ip($ip); - } - - /** - * Encodes an IP address - * - * Takes a human readable IP address into a base64-encoded "blob" - * - * @param string $ip - * @access private - * @return string - */ - function _encodeIP($ip) - { - return base64_encode(pack('N', ip2long($ip))); - } - - /** - * "Normalizes" a Distinguished Name property - * - * @param string $propName - * @access private - * @return mixed - */ - function _translateDNProp($propName) - { - switch (strtolower($propName)) { - case 'id-at-countryname': - case 'countryname': - case 'c': - return 'id-at-countryName'; - case 'id-at-organizationname': - case 'organizationname': - case 'o': - return 'id-at-organizationName'; - case 'id-at-dnqualifier': - case 'dnqualifier': - return 'id-at-dnQualifier'; - case 'id-at-commonname': - case 'commonname': - case 'cn': - return 'id-at-commonName'; - case 'id-at-stateorprovincename': - case 'stateorprovincename': - case 'state': - case 'province': - case 'provincename': - case 'st': - return 'id-at-stateOrProvinceName'; - case 'id-at-localityname': - case 'localityname': - case 'l': - return 'id-at-localityName'; - case 'id-emailaddress': - case 'emailaddress': - return 'pkcs-9-at-emailAddress'; - case 'id-at-serialnumber': - case 'serialnumber': - return 'id-at-serialNumber'; - case 'id-at-postalcode': - case 'postalcode': - return 'id-at-postalCode'; - case 'id-at-streetaddress': - case 'streetaddress': - return 'id-at-streetAddress'; - case 'id-at-name': - case 'name': - return 'id-at-name'; - case 'id-at-givenname': - case 'givenname': - return 'id-at-givenName'; - case 'id-at-surname': - case 'surname': - case 'sn': - return 'id-at-surname'; - case 'id-at-initials': - case 'initials': - return 'id-at-initials'; - case 'id-at-generationqualifier': - case 'generationqualifier': - return 'id-at-generationQualifier'; - case 'id-at-organizationalunitname': - case 'organizationalunitname': - case 'ou': - return 'id-at-organizationalUnitName'; - case 'id-at-pseudonym': - case 'pseudonym': - return 'id-at-pseudonym'; - case 'id-at-title': - case 'title': - return 'id-at-title'; - case 'id-at-description': - case 'description': - return 'id-at-description'; - case 'id-at-role': - case 'role': - return 'id-at-role'; - case 'id-at-uniqueidentifier': - case 'uniqueidentifier': - case 'x500uniqueidentifier': - return 'id-at-uniqueIdentifier'; - case 'postaladdress': - case 'id-at-postaladdress': - return 'id-at-postalAddress'; - default: - return false; - } - } - - /** - * Set a Distinguished Name property - * - * @param string $propName - * @param mixed $propValue - * @param string $type optional - * @access public - * @return bool - */ - function setDNProp($propName, $propValue, $type = 'utf8String') - { - if (empty($this->dn)) { - $this->dn = array('rdnSequence' => array()); - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return false; - } - - foreach ((array) $propValue as $v) { - if (!is_array($v) && isset($type)) { - $v = array($type => $v); - } - $this->dn['rdnSequence'][] = array( - array( - 'type' => $propName, - 'value'=> $v - ) - ); - } - - return true; - } - - /** - * Remove Distinguished Name properties - * - * @param string $propName - * @access public - */ - function removeDNProp($propName) - { - if (empty($this->dn)) { - return; - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return; - } - - $dn = &$this->dn['rdnSequence']; - $size = count($dn); - for ($i = 0; $i < $size; $i++) { - if ($dn[$i][0]['type'] == $propName) { - unset($dn[$i]); - } - } - - $dn = array_values($dn); - } - - /** - * Get Distinguished Name properties - * - * @param string $propName - * @param array $dn optional - * @param bool $withType optional - * @return mixed - * @access public - */ - function getDNProp($propName, $dn = null, $withType = false) - { - if (!isset($dn)) { - $dn = $this->dn; - } - - if (empty($dn)) { - return false; - } - - if (($propName = $this->_translateDNProp($propName)) === false) { - return false; - } - - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - $this->_mapOutDNs($dn, 'rdnSequence', $asn1); - $dn = $dn['rdnSequence']; - $result = array(); - for ($i = 0; $i < count($dn); $i++) { - if ($dn[$i][0]['type'] == $propName) { - $v = $dn[$i][0]['value']; - if (!$withType) { - if (is_array($v)) { - foreach ($v as $type => $s) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $s = $asn1->convert($s, $type); - if ($s !== false) { - $v = $s; - break; - } - } - } - if (is_array($v)) { - $v = array_pop($v); // Always strip data type. - } - } elseif (is_object($v) && strtolower(get_class($v)) == 'file_asn1_element') { - $map = $this->_getMapping($propName); - if (!is_bool($map)) { - $decoded = $asn1->decodeBER($v); - $v = $asn1->asn1map($decoded[0], $map); - } - } - } - $result[] = $v; - } - } - - return $result; - } - - /** - * Set a Distinguished Name - * - * @param mixed $dn - * @param bool $merge optional - * @param string $type optional - * @access public - * @return bool - */ - function setDN($dn, $merge = false, $type = 'utf8String') - { - if (!$merge) { - $this->dn = null; - } - - if (is_array($dn)) { - if (isset($dn['rdnSequence'])) { - $this->dn = $dn; // No merge here. - return true; - } - - // handles stuff generated by openssl_x509_parse() - foreach ($dn as $prop => $value) { - if (!$this->setDNProp($prop, $value, $type)) { - return false; - } - } - return true; - } - - // handles everything else - $results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 1; $i < count($results); $i+=2) { - $prop = trim($results[$i], ', =/'); - $value = $results[$i + 1]; - if (!$this->setDNProp($prop, $value, $type)) { - return false; - } - } - - return true; - } - - /** - * Get the Distinguished Name for a certificates subject - * - * @param mixed $format optional - * @param array $dn optional - * @access public - * @return bool - */ - function getDN($format = FILE_X509_DN_ARRAY, $dn = null) - { - if (!isset($dn)) { - $dn = isset($this->currentCert['tbsCertList']) ? $this->currentCert['tbsCertList']['issuer'] : $this->dn; - } - - switch ((int) $format) { - case FILE_X509_DN_ARRAY: - return $dn; - case FILE_X509_DN_ASN1: - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - $this->_mapOutDNs($dn, 'rdnSequence', $asn1); - return $asn1->encodeDER($dn, $this->Name); - case FILE_X509_DN_CANON: - // No SEQUENCE around RDNs and all string values normalized as - // trimmed lowercase UTF-8 with all spacing as one blank. - // constructed RDNs will not be canonicalized - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - $result = ''; - $this->_mapOutDNs($dn, 'rdnSequence', $asn1); - foreach ($dn['rdnSequence'] as $rdn) { - foreach ($rdn as $i => $attr) { - $attr = &$rdn[$i]; - if (is_array($attr['value'])) { - foreach ($attr['value'] as $type => $v) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $v = $asn1->convert($v, $type); - if ($v !== false) { - $v = preg_replace('/\s+/', ' ', $v); - $attr['value'] = strtolower(trim($v)); - break; - } - } - } - } - } - $result .= $asn1->encodeDER($rdn, $this->RelativeDistinguishedName); - } - return $result; - case FILE_X509_DN_HASH: - $dn = $this->getDN(FILE_X509_DN_CANON, $dn); - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hash = new Crypt_Hash('sha1'); - $hash = $hash->hash($dn); - extract(unpack('Vhash', $hash)); - return strtolower(bin2hex(pack('N', $hash))); - } - - // Default is to return a string. - $start = true; - $output = ''; - $result = array(); - $asn1 = new File_ASN1(); - $asn1->loadOIDs($this->oids); - $filters = array(); - $filters['rdnSequence']['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $asn1->loadFilters($filters); - $this->_mapOutDNs($dn, 'rdnSequence', $asn1); - foreach ($dn['rdnSequence'] as $field) { - $prop = $field[0]['type']; - $value = $field[0]['value']; - - $delim = ', '; - switch ($prop) { - case 'id-at-countryName': - $desc = 'C'; - break; - case 'id-at-stateOrProvinceName': - $desc = 'ST'; - break; - case 'id-at-organizationName': - $desc = 'O'; - break; - case 'id-at-organizationalUnitName': - $desc = 'OU'; - break; - case 'id-at-commonName': - $desc = 'CN'; - break; - case 'id-at-localityName': - $desc = 'L'; - break; - case 'id-at-surname': - $desc = 'SN'; - break; - case 'id-at-uniqueIdentifier': - $delim = '/'; - $desc = 'x500UniqueIdentifier'; - break; - case 'id-at-postalAddress': - $delim = '/'; - $desc = 'postalAddress'; - break; - default: - $delim = '/'; - $desc = preg_replace('#.+-([^-]+)$#', '$1', $prop); - } - - if (!$start) { - $output.= $delim; - } - if (is_array($value)) { - foreach ($value as $type => $v) { - $type = array_search($type, $asn1->ANYmap, true); - if ($type !== false && isset($asn1->stringTypeSize[$type])) { - $v = $asn1->convert($v, $type); - if ($v !== false) { - $value = $v; - break; - } - } - } - if (is_array($value)) { - $value = array_pop($value); // Always strip data type. - } - } elseif (is_object($value) && strtolower(get_class($value)) == 'file_asn1_element') { - $callback = create_function('$x', 'return "\x" . bin2hex($x[0]);'); - $value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element)); - } - $output.= $desc . '=' . $value; - $result[$desc] = isset($result[$desc]) ? - array_merge((array) $dn[$prop], array($value)) : - $value; - $start = false; - } - - return $format == FILE_X509_DN_OPENSSL ? $result : $output; - } - - /** - * Get the Distinguished Name for a certificate/crl issuer - * - * @param int $format optional - * @access public - * @return mixed - */ - function getIssuerDN($format = FILE_X509_DN_ARRAY) - { - switch (true) { - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDN($format, $this->currentCert['tbsCertificate']['issuer']); - case isset($this->currentCert['tbsCertList']): - return $this->getDN($format, $this->currentCert['tbsCertList']['issuer']); - } - - return false; - } - - /** - * Get the Distinguished Name for a certificate/csr subject - * Alias of getDN() - * - * @param int $format optional - * @access public - * @return mixed - */ - function getSubjectDN($format = FILE_X509_DN_ARRAY) - { - switch (true) { - case !empty($this->dn): - return $this->getDN($format); - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDN($format, $this->currentCert['tbsCertificate']['subject']); - case isset($this->currentCert['certificationRequestInfo']): - return $this->getDN($format, $this->currentCert['certificationRequestInfo']['subject']); - } - - return false; - } - - /** - * Get an individual Distinguished Name property for a certificate/crl issuer - * - * @param string $propName - * @param bool $withType optional - * @access public - * @return mixed - */ - function getIssuerDNProp($propName, $withType = false) - { - switch (true) { - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['issuer'], $withType); - case isset($this->currentCert['tbsCertList']): - return $this->getDNProp($propName, $this->currentCert['tbsCertList']['issuer'], $withType); - } - - return false; - } - - /** - * Get an individual Distinguished Name property for a certificate/csr subject - * - * @param string $propName - * @param bool $withType optional - * @access public - * @return mixed - */ - function getSubjectDNProp($propName, $withType = false) - { - switch (true) { - case !empty($this->dn): - return $this->getDNProp($propName, null, $withType); - case !isset($this->currentCert) || !is_array($this->currentCert): - break; - case isset($this->currentCert['tbsCertificate']): - return $this->getDNProp($propName, $this->currentCert['tbsCertificate']['subject'], $withType); - case isset($this->currentCert['certificationRequestInfo']): - return $this->getDNProp($propName, $this->currentCert['certificationRequestInfo']['subject'], $withType); - } - - return false; - } - - /** - * Get the certificate chain for the current cert - * - * @access public - * @return mixed - */ - function getChain() - { - $chain = array($this->currentCert); - - if (!is_array($this->currentCert) || !isset($this->currentCert['tbsCertificate'])) { - return false; - } - if (empty($this->CAs)) { - return $chain; - } - while (true) { - $currentCert = $chain[count($chain) - 1]; - for ($i = 0; $i < count($this->CAs); $i++) { - $ca = $this->CAs[$i]; - if ($currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) { - $authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier', $currentCert); - $subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca); - switch (true) { - case !is_array($authorityKey): - case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID: - if ($currentCert === $ca) { - break 3; - } - $chain[] = $ca; - break 2; - } - } - } - if ($i == count($this->CAs)) { - break; - } - } - foreach ($chain as $key => $value) { - $chain[$key] = new File_X509(); - $chain[$key]->loadX509($value); - } - return $chain; - } - - /** - * Set public key - * - * Key needs to be a Crypt_RSA object - * - * @param object $key - * @access public - * @return bool - */ - function setPublicKey($key) - { - $key->setPublicKey(); - $this->publicKey = $key; - } - - /** - * Set private key - * - * Key needs to be a Crypt_RSA object - * - * @param object $key - * @access public - */ - function setPrivateKey($key) - { - $this->privateKey = $key; - } - - /** - * Set challenge - * - * Used for SPKAC CSR's - * - * @param string $challenge - * @access public - */ - function setChallenge($challenge) - { - $this->challenge = $challenge; - } - - /** - * Gets the public key - * - * Returns a Crypt_RSA object or a false. - * - * @access public - * @return mixed - */ - function getPublicKey() - { - if (isset($this->publicKey)) { - return $this->publicKey; - } - - if (isset($this->currentCert) && is_array($this->currentCert)) { - foreach (array('tbsCertificate/subjectPublicKeyInfo', 'certificationRequestInfo/subjectPKInfo') as $path) { - $keyinfo = $this->_subArray($this->currentCert, $path); - if (!empty($keyinfo)) { - break; - } - } - } - if (empty($keyinfo)) { - return false; - } - - $key = $keyinfo['subjectPublicKey']; - - switch ($keyinfo['algorithm']['algorithm']) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $publicKey = new Crypt_RSA(); - $publicKey->loadKey($key); - $publicKey->setPublicKey(); - break; - default: - return false; - } - - return $publicKey; - } - - /** - * Load a Certificate Signing Request - * - * @param string $csr - * @access public - * @return mixed - */ - function loadCSR($csr, $mode = FILE_X509_FORMAT_AUTO_DETECT) - { - if (is_array($csr) && isset($csr['certificationRequestInfo'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - unset($this->signatureSubject); - $this->dn = $csr['certificationRequestInfo']['subject']; - if (!isset($this->dn)) { - return false; - } - - $this->currentCert = $csr; - return $csr; - } - - // see http://tools.ietf.org/html/rfc2986 - - $asn1 = new File_ASN1(); - - if ($mode != FILE_X509_FORMAT_DER) { - $newcsr = $this->_extractBER($csr); - if ($mode == FILE_X509_FORMAT_PEM && $csr == $newcsr) { - return false; - } - $csr = $newcsr; - } - $orig = $csr; - - if ($csr === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($csr); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $csr = $asn1->asn1map($decoded[0], $this->CertificationRequest); - if (!isset($csr) || $csr === false) { - $this->currentCert = false; - return false; - } - - $this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1); - $this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1); - - $this->dn = $csr['certificationRequestInfo']['subject']; - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm']; - $key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']; - $key = $this->_reformatKey($algorithm, $key); - - switch ($algorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($key); - $this->publicKey->setPublicKey(); - break; - default: - $this->publicKey = null; - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $csr; - - return $csr; - } - - /** - * Save CSR request - * - * @param array $csr - * @param int $format optional - * @access public - * @return string - */ - function saveCSR($csr, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) { - return false; - } - - switch (true) { - case !($algorithm = $this->_subArray($csr, 'certificationRequestInfo/subjectPKInfo/algorithm/algorithm')): - case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']): - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))); - $csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null; - $csr['signatureAlgorithm']['parameters'] = null; - $csr['certificationRequestInfo']['signature']['parameters'] = null; - } - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - - $filters = array(); - $filters['certificationRequestInfo']['subject']['rdnSequence']['value'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - - $asn1->loadFilters($filters); - - $this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1); - $this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1); - $csr = $asn1->encodeDER($csr, $this->CertificationRequest); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $csr; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----'; - } - } - - /** - * Load a SPKAC CSR - * - * SPKAC's are produced by the HTML5 keygen element: - * - * https://developer.mozilla.org/en-US/docs/HTML/Element/keygen - * - * @param string $csr - * @access public - * @return mixed - */ - function loadSPKAC($spkac) - { - if (is_array($spkac) && isset($spkac['publicKeyAndChallenge'])) { - unset($this->currentCert); - unset($this->currentKeyIdentifier); - unset($this->signatureSubject); - $this->currentCert = $spkac; - return $spkac; - } - - // see http://www.w3.org/html/wg/drafts/html/master/forms.html#signedpublickeyandchallenge - - $asn1 = new File_ASN1(); - - // OpenSSL produces SPKAC's that are preceded by the string SPKAC= - $temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - if ($temp != false) { - $spkac = $temp; - } - $orig = $spkac; - - if ($spkac === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($spkac); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $spkac = $asn1->asn1map($decoded[0], $this->SignedPublicKeyAndChallenge); - - if (!isset($spkac) || $spkac === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm']; - $key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']; - $key = $this->_reformatKey($algorithm, $key); - - switch ($algorithm) { - case 'rsaEncryption': - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $this->publicKey = new Crypt_RSA(); - $this->publicKey->loadKey($key); - $this->publicKey->setPublicKey(); - break; - default: - $this->publicKey = null; - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $spkac; - - return $spkac; - } - - /** - * Save a SPKAC CSR request - * - * @param array $csr - * @param int $format optional - * @access public - * @return string - */ - function saveSPKAC($spkac, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($spkac) || !isset($spkac['publicKeyAndChallenge'])) { - return false; - } - - $algorithm = $this->_subArray($spkac, 'publicKeyAndChallenge/spki/algorithm/algorithm'); - switch (true) { - case !$algorithm: - case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']): - break; - default: - switch ($algorithm) { - case 'rsaEncryption': - $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] - = base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']))); - } - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - $spkac = $asn1->encodeDER($spkac, $this->SignedPublicKeyAndChallenge); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $spkac; - // case FILE_X509_FORMAT_PEM: - default: - // OpenSSL's implementation of SPKAC requires the SPKAC be preceded by SPKAC= and since there are pretty much - // no other SPKAC decoders phpseclib will use that same format - return 'SPKAC=' . base64_encode($spkac); - } - } - - /** - * Load a Certificate Revocation List - * - * @param string $crl - * @access public - * @return mixed - */ - function loadCRL($crl, $mode = FILE_X509_FORMAT_AUTO_DETECT) - { - if (is_array($crl) && isset($crl['tbsCertList'])) { - $this->currentCert = $crl; - unset($this->signatureSubject); - return $crl; - } - - $asn1 = new File_ASN1(); - - if ($mode != FILE_X509_FORMAT_DER) { - $newcrl = $this->_extractBER($crl); - if ($mode == FILE_X509_FORMAT_PEM && $crl == $newcrl) { - return false; - } - $crl = $newcrl; - } - $orig = $crl; - - if ($crl === false) { - $this->currentCert = false; - return false; - } - - $asn1->loadOIDs($this->oids); - $decoded = $asn1->decodeBER($crl); - - if (empty($decoded)) { - $this->currentCert = false; - return false; - } - - $crl = $asn1->asn1map($decoded[0], $this->CertificateList); - if (!isset($crl) || $crl === false) { - $this->currentCert = false; - return false; - } - - $this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']); - - $this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1); - if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) { - $this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - } - if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) { - $rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates'); - if ($rclist_ref) { - $rclist = $crl['tbsCertList']['revokedCertificates']; - foreach ($rclist as $i => $extension) { - if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) { - $this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1); - } - } - } - } - - $this->currentKeyIdentifier = null; - $this->currentCert = $crl; - - return $crl; - } - - /** - * Save Certificate Revocation List. - * - * @param array $crl - * @param int $format optional - * @access public - * @return string - */ - function saveCRL($crl, $format = FILE_X509_FORMAT_PEM) - { - if (!is_array($crl) || !isset($crl['tbsCertList'])) { - return false; - } - - $asn1 = new File_ASN1(); - - $asn1->loadOIDs($this->oids); - - $filters = array(); - $filters['tbsCertList']['issuer']['rdnSequence']['value'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['tbsCertList']['signature']['parameters'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - $filters['signatureAlgorithm']['parameters'] - = array('type' => FILE_ASN1_TYPE_UTF8_STRING); - - if (empty($crl['tbsCertList']['signature']['parameters'])) { - $filters['tbsCertList']['signature']['parameters'] - = array('type' => FILE_ASN1_TYPE_NULL); - } - - if (empty($crl['signatureAlgorithm']['parameters'])) { - $filters['signatureAlgorithm']['parameters'] - = array('type' => FILE_ASN1_TYPE_NULL); - } - - $asn1->loadFilters($filters); - - $this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1); - $this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1); - $rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates'); - if (is_array($rclist)) { - foreach ($rclist as $i => $extension) { - $this->_mapOutExtensions($rclist, "$i/crlEntryExtensions", $asn1); - } - } - - $crl = $asn1->encodeDER($crl, $this->CertificateList); - - switch ($format) { - case FILE_X509_FORMAT_DER: - return $crl; - // case FILE_X509_FORMAT_PEM: - default: - return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----'; - } - } - - /** - * Helper function to build a time field according to RFC 3280 section - * - 4.1.2.5 Validity - * - 5.1.2.4 This Update - * - 5.1.2.5 Next Update - * - 5.1.2.6 Revoked Certificates - * by choosing utcTime iff year of date given is before 2050 and generalTime else. - * - * @param string $date in format date('D, d M Y H:i:s O') - * @access private - * @return array - */ - function _timeField($date) - { - $year = @gmdate("Y", @strtotime($date)); // the same way ASN1.php parses this - if ($year < 2050) { - return array('utcTime' => $date); - } else { - return array('generalTime' => $date); - } - } - - /** - * Sign an X.509 certificate - * - * $issuer's private key needs to be loaded. - * $subject can be either an existing X.509 cert (if you want to resign it), - * a CSR or something with the DN and public key explicitly set. - * - * @param File_X509 $issuer - * @param File_X509 $subject - * @param string $signatureAlgorithm optional - * @access public - * @return mixed - */ - function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($issuer->privateKey) || empty($issuer->dn)) { - return false; - } - - if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) { - return false; - } - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) { - $this->currentCert = $subject->currentCert; - $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm; - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - - if (!empty($this->startDate)) { - $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate); - } - if (!empty($this->endDate)) { - $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate); - } - if (!empty($this->serialNumber)) { - $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber; - } - if (!empty($subject->dn)) { - $this->currentCert['tbsCertificate']['subject'] = $subject->dn; - } - if (!empty($subject->publicKey)) { - $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey; - } - $this->removeExtension('id-ce-authorityKeyIdentifier'); - if (isset($subject->domains)) { - $this->removeExtension('id-ce-subjectAltName'); - } - } elseif (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) { - return false; - } else { - if (!isset($subject->publicKey)) { - return false; - } - - $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); - $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year')); - if (!empty($this->serialNumber)) { - $serialNumber = $this->serialNumber; - } else { - if (!function_exists('crypt_random_string')) { - include_once 'Crypt/Random.php'; - } - /* "The serial number MUST be a positive integer" - "Conforming CAs MUST NOT use serialNumber values longer than 20 octets." - -- https://tools.ietf.org/html/rfc5280#section-4.1.2.2 - - for the integer to be positive the leading bit needs to be 0 hence the - application of a bitmap - */ - $serialNumber = new Math_BigInteger(crypt_random_string(20) & ("\x7F" . str_repeat("\xFF", 19)), 256); - } - - $this->currentCert = array( - 'tbsCertificate' => - array( - 'version' => 'v3', - 'serialNumber' => $serialNumber, // $this->setserialNumber() - 'signature' => array('algorithm' => $signatureAlgorithm), - 'issuer' => false, // this is going to be overwritten later - 'validity' => array( - 'notBefore' => $this->_timeField($startDate), // $this->setStartDate() - 'notAfter' => $this->_timeField($endDate) // $this->setEndDate() - ), - 'subject' => $subject->dn, - 'subjectPublicKeyInfo' => $subjectPublicKey - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - - // Copy extensions from CSR. - $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0); - - if (!empty($csrexts)) { - $this->currentCert['tbsCertificate']['extensions'] = $csrexts; - } - } - - $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn; - - if (isset($issuer->currentKeyIdentifier)) { - $this->setExtension('id-ce-authorityKeyIdentifier', array( - //'authorityCertIssuer' => array( - // array( - // 'directoryName' => $issuer->dn - // ) - //), - 'keyIdentifier' => $issuer->currentKeyIdentifier - )); - //$extensions = &$this->currentCert['tbsCertificate']['extensions']; - //if (isset($issuer->serialNumber)) { - // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; - //} - //unset($extensions); - } - - if (isset($subject->currentKeyIdentifier)) { - $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier); - } - - $altName = array(); - - if (isset($subject->domains) && count($subject->domains) > 1) { - $altName = array_map(array('File_X509', '_dnsName'), $subject->domains); - } - - if (isset($subject->ipAddresses) && count($subject->ipAddresses)) { - // should an IP address appear as the CN if no domain name is specified? idk - //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1); - $ipAddresses = array(); - foreach ($subject->ipAddresses as $ipAddress) { - $encoded = $subject->_ipAddress($ipAddress); - if ($encoded !== false) { - $ipAddresses[] = $encoded; - } - } - if (count($ipAddresses)) { - $altName = array_merge($altName, $ipAddresses); - } - } - - if (!empty($altName)) { - $this->setExtension('id-ce-subjectAltName', $altName); - } - - if ($this->caFlag) { - $keyUsage = $this->getExtension('id-ce-keyUsage'); - if (!$keyUsage) { - $keyUsage = array(); - } - - $this->setExtension( - 'id-ce-keyUsage', - array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign')))) - ); - - $basicConstraints = $this->getExtension('id-ce-basicConstraints'); - if (!$basicConstraints) { - $basicConstraints = array(); - } - - $this->setExtension( - 'id-ce-basicConstraints', - array_unique(array_merge(array('cA' => true), $basicConstraints)), - true - ); - - if (!isset($subject->currentKeyIdentifier)) { - $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false); - } - } - - // resync $this->signatureSubject - // save $tbsCertificate in case there are any File_ASN1_Element objects in it - $tbsCertificate = $this->currentCert['tbsCertificate']; - $this->loadX509($this->saveX509($this->currentCert)); - - $result = $this->_sign($issuer->privateKey, $signatureAlgorithm); - $result['tbsCertificate'] = $tbsCertificate; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a CSR - * - * @access public - * @return mixed - */ - function signCSR($signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($this->privateKey) || empty($this->dn)) { - return false; - } - - $origPublicKey = $this->publicKey; - $class = get_class($this->privateKey); - $this->publicKey = new $class(); - $this->publicKey->loadKey($this->privateKey->getPublicKey()); - $this->publicKey->setPublicKey(); - if (!($publicKey = $this->_formatSubjectPublicKey())) { - return false; - } - $this->publicKey = $origPublicKey; - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) { - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - if (!empty($this->dn)) { - $this->currentCert['certificationRequestInfo']['subject'] = $this->dn; - } - $this->currentCert['certificationRequestInfo']['subjectPKInfo'] = $publicKey; - } else { - $this->currentCert = array( - 'certificationRequestInfo' => - array( - 'version' => 'v1', - 'subject' => $this->dn, - 'subjectPKInfo' => $publicKey - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - // resync $this->signatureSubject - // save $certificationRequestInfo in case there are any File_ASN1_Element objects in it - $certificationRequestInfo = $this->currentCert['certificationRequestInfo']; - $this->loadCSR($this->saveCSR($this->currentCert)); - - $result = $this->_sign($this->privateKey, $signatureAlgorithm); - $result['certificationRequestInfo'] = $certificationRequestInfo; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a SPKAC - * - * @access public - * @return mixed - */ - function signSPKAC($signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($this->privateKey)) { - return false; - } - - $origPublicKey = $this->publicKey; - $class = get_class($this->privateKey); - $this->publicKey = new $class(); - $this->publicKey->loadKey($this->privateKey->getPublicKey()); - $this->publicKey->setPublicKey(); - $publicKey = $this->_formatSubjectPublicKey(); - if (!$publicKey) { - return false; - } - $this->publicKey = $origPublicKey; - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null; - - // re-signing a SPKAC seems silly but since everything else supports re-signing why not? - if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) { - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - $this->currentCert['publicKeyAndChallenge']['spki'] = $publicKey; - if (!empty($this->challenge)) { - // the bitwise AND ensures that the output is a valid IA5String - $this->currentCert['publicKeyAndChallenge']['challenge'] = $this->challenge & str_repeat("\x7F", strlen($this->challenge)); - } - } else { - $this->currentCert = array( - 'publicKeyAndChallenge' => - array( - 'spki' => $publicKey, - // quoting <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen>, - // "A challenge string that is submitted along with the public key. Defaults to an empty string if not specified." - // both Firefox and OpenSSL ("openssl spkac -key private.key") behave this way - // we could alternatively do this instead if we ignored the specs: - // crypt_random_string(8) & str_repeat("\x7F", 8) - 'challenge' => !empty($this->challenge) ? $this->challenge : '' - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - // resync $this->signatureSubject - // save $publicKeyAndChallenge in case there are any File_ASN1_Element objects in it - $publicKeyAndChallenge = $this->currentCert['publicKeyAndChallenge']; - $this->loadSPKAC($this->saveSPKAC($this->currentCert)); - - $result = $this->_sign($this->privateKey, $signatureAlgorithm); - $result['publicKeyAndChallenge'] = $publicKeyAndChallenge; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * Sign a CRL - * - * $issuer's private key needs to be loaded. - * - * @param File_X509 $issuer - * @param File_X509 $crl - * @param string $signatureAlgorithm optional - * @access public - * @return mixed - */ - function signCRL($issuer, $crl, $signatureAlgorithm = 'sha1WithRSAEncryption') - { - if (!is_object($issuer->privateKey) || empty($issuer->dn)) { - return false; - } - - $currentCert = isset($this->currentCert) ? $this->currentCert : null; - $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null; - $thisUpdate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O'); - - if (isset($crl->currentCert) && is_array($crl->currentCert) && isset($crl->currentCert['tbsCertList'])) { - $this->currentCert = $crl->currentCert; - $this->currentCert['tbsCertList']['signature']['algorithm'] = $signatureAlgorithm; - $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm; - } else { - $this->currentCert = array( - 'tbsCertList' => - array( - 'version' => 'v2', - 'signature' => array('algorithm' => $signatureAlgorithm), - 'issuer' => false, // this is going to be overwritten later - 'thisUpdate' => $this->_timeField($thisUpdate) // $this->setStartDate() - ), - 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), - 'signature' => false // this is going to be overwritten later - ); - } - - $tbsCertList = &$this->currentCert['tbsCertList']; - $tbsCertList['issuer'] = $issuer->dn; - $tbsCertList['thisUpdate'] = $this->_timeField($thisUpdate); - - if (!empty($this->endDate)) { - $tbsCertList['nextUpdate'] = $this->_timeField($this->endDate); // $this->setEndDate() - } else { - unset($tbsCertList['nextUpdate']); - } - - if (!empty($this->serialNumber)) { - $crlNumber = $this->serialNumber; - } else { - $crlNumber = $this->getExtension('id-ce-cRLNumber'); - // "The CRL number is a non-critical CRL extension that conveys a - // monotonically increasing sequence number for a given CRL scope and - // CRL issuer. This extension allows users to easily determine when a - // particular CRL supersedes another CRL." - // -- https://tools.ietf.org/html/rfc5280#section-5.2.3 - $crlNumber = $crlNumber !== false ? $crlNumber->add(new Math_BigInteger(1)) : null; - } - - $this->removeExtension('id-ce-authorityKeyIdentifier'); - $this->removeExtension('id-ce-issuerAltName'); - - // Be sure version >= v2 if some extension found. - $version = isset($tbsCertList['version']) ? $tbsCertList['version'] : 0; - if (!$version) { - if (!empty($tbsCertList['crlExtensions'])) { - $version = 1; // v2. - } elseif (!empty($tbsCertList['revokedCertificates'])) { - foreach ($tbsCertList['revokedCertificates'] as $cert) { - if (!empty($cert['crlEntryExtensions'])) { - $version = 1; // v2. - } - } - } - - if ($version) { - $tbsCertList['version'] = $version; - } - } - - // Store additional extensions. - if (!empty($tbsCertList['version'])) { // At least v2. - if (!empty($crlNumber)) { - $this->setExtension('id-ce-cRLNumber', $crlNumber); - } - - if (isset($issuer->currentKeyIdentifier)) { - $this->setExtension('id-ce-authorityKeyIdentifier', array( - //'authorityCertIssuer' => array( - // array( - // 'directoryName' => $issuer->dn - // ) - //), - 'keyIdentifier' => $issuer->currentKeyIdentifier - )); - //$extensions = &$tbsCertList['crlExtensions']; - //if (isset($issuer->serialNumber)) { - // $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber; - //} - //unset($extensions); - } - - $issuerAltName = $this->getExtension('id-ce-subjectAltName', $issuer->currentCert); - - if ($issuerAltName !== false) { - $this->setExtension('id-ce-issuerAltName', $issuerAltName); - } - } - - if (empty($tbsCertList['revokedCertificates'])) { - unset($tbsCertList['revokedCertificates']); - } - - unset($tbsCertList); - - // resync $this->signatureSubject - // save $tbsCertList in case there are any File_ASN1_Element objects in it - $tbsCertList = $this->currentCert['tbsCertList']; - $this->loadCRL($this->saveCRL($this->currentCert)); - - $result = $this->_sign($issuer->privateKey, $signatureAlgorithm); - $result['tbsCertList'] = $tbsCertList; - - $this->currentCert = $currentCert; - $this->signatureSubject = $signatureSubject; - - return $result; - } - - /** - * X.509 certificate signing helper function. - * - * @param object $key - * @param File_X509 $subject - * @param string $signatureAlgorithm - * @access public - * @return mixed - */ - function _sign($key, $signatureAlgorithm) - { - switch (strtolower(get_class($key))) { - case 'crypt_rsa': - switch ($signatureAlgorithm) { - case 'md2WithRSAEncryption': - case 'md5WithRSAEncryption': - case 'sha1WithRSAEncryption': - case 'sha224WithRSAEncryption': - case 'sha256WithRSAEncryption': - case 'sha384WithRSAEncryption': - case 'sha512WithRSAEncryption': - $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $key->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); - - $this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject)); - return $this->currentCert; - } - default: - return false; - } - } - - /** - * Set certificate start date - * - * @param string $date - * @access public - */ - function setStartDate($date) - { - $this->startDate = @date('D, d M Y H:i:s O', @strtotime($date)); - } - - /** - * 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 File_ASN1(); - $temp = chr(FILE_ASN1_TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp; - $this->endDate = new File_ASN1_Element($temp); - } else { - $this->endDate = @date('D, d M Y H:i:s O', @strtotime($date)); - } - } - - /** - * Set Serial Number - * - * @param string $serial - * @param $base optional - * @access public - */ - function setSerialNumber($serial, $base = -256) - { - $this->serialNumber = new Math_BigInteger($serial, $base); - } - - /** - * Turns the certificate into a certificate authority - * - * @access public - */ - function makeCA() - { - $this->caFlag = true; - } - - /** - * Check for validity of subarray - * - * This is intended for use in conjunction with _subArrayUnchecked(), - * implementing the checks included in _subArray() but without copying - * a potentially large array by passing its reference by-value to is_array(). - * - * @param array $root - * @param string $path - * @return boolean - * @access private - */ - function _isSubArrayValid($root, $path) - { - if (!is_array($root)) { - return false; - } - - foreach (explode('/', $path) as $i) { - if (!is_array($root)) { - return false; - } - - if (!isset($root[$i])) { - return true; - } - - $root = $root[$i]; - } - - return true; - } - - /** - * Get a reference to a subarray - * - * This variant of _subArray() does no is_array() checking, - * so $root should be checked with _isSubArrayValid() first. - * - * This is here for performance reasons: - * Passing a reference (i.e. $root) by-value (i.e. to is_array()) - * creates a copy. If $root is an especially large array, this is expensive. - * - * @param array $root - * @param string $path absolute path with / as component separator - * @param bool $create optional - * @access private - * @return array|false - */ - function &_subArrayUnchecked(&$root, $path, $create = false) - { - $false = false; - - foreach (explode('/', $path) as $i) { - if (!isset($root[$i])) { - if (!$create) { - return $false; - } - - $root[$i] = array(); - } - - $root = &$root[$i]; - } - - return $root; - } - - /** - * Get a reference to a subarray - * - * @param array $root - * @param string $path absolute path with / as component separator - * @param bool $create optional - * @access private - * @return array|false - */ - function &_subArray(&$root, $path, $create = false) - { - $false = false; - - if (!is_array($root)) { - return $false; - } - - foreach (explode('/', $path) as $i) { - if (!is_array($root)) { - return $false; - } - - if (!isset($root[$i])) { - if (!$create) { - return $false; - } - - $root[$i] = array(); - } - - $root = &$root[$i]; - } - - return $root; - } - - /** - * Get a reference to an extension subarray - * - * @param array $root - * @param string $path optional absolute path with / as component separator - * @param bool $create optional - * @access private - * @return array|false - */ - function &_extensions(&$root, $path = null, $create = false) - { - if (!isset($root)) { - $root = $this->currentCert; - } - - switch (true) { - case !empty($path): - case !is_array($root): - break; - case isset($root['tbsCertificate']): - $path = 'tbsCertificate/extensions'; - break; - case isset($root['tbsCertList']): - $path = 'tbsCertList/crlExtensions'; - break; - case isset($root['certificationRequestInfo']): - $pth = 'certificationRequestInfo/attributes'; - $attributes = &$this->_subArray($root, $pth, $create); - - if (is_array($attributes)) { - foreach ($attributes as $key => $value) { - if ($value['type'] == 'pkcs-9-at-extensionRequest') { - $path = "$pth/$key/value/0"; - break 2; - } - } - if ($create) { - $key = count($attributes); - $attributes[] = array('type' => 'pkcs-9-at-extensionRequest', 'value' => array()); - $path = "$pth/$key/value/0"; - } - } - break; - } - - $extensions = &$this->_subArray($root, $path, $create); - - if (!is_array($extensions)) { - $false = false; - return $false; - } - - return $extensions; - } - - /** - * Remove an Extension - * - * @param string $id - * @param string $path optional - * @access private - * @return bool - */ - function _removeExtension($id, $path = null) - { - $extensions = &$this->_extensions($this->currentCert, $path); - - if (!is_array($extensions)) { - return false; - } - - $result = false; - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - unset($extensions[$key]); - $result = true; - } - } - - $extensions = array_values($extensions); - return $result; - } - - /** - * Get an Extension - * - * Returns the extension if it exists and false if not - * - * @param string $id - * @param array $cert optional - * @param string $path optional - * @access private - * @return mixed - */ - function _getExtension($id, $cert = null, $path = null) - { - $extensions = $this->_extensions($cert, $path); - - if (!is_array($extensions)) { - return false; - } - - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - return $value['extnValue']; - } - } - - return false; - } - - /** - * Returns a list of all extensions in use - * - * @param array $cert optional - * @param string $path optional - * @access private - * @return array - */ - function _getExtensions($cert = null, $path = null) - { - $exts = $this->_extensions($cert, $path); - $extensions = array(); - - if (is_array($exts)) { - foreach ($exts as $extension) { - $extensions[] = $extension['extnId']; - } - } - - return $extensions; - } - - /** - * Set an Extension - * - * @param string $id - * @param mixed $value - * @param bool $critical optional - * @param bool $replace optional - * @param string $path optional - * @access private - * @return bool - */ - function _setExtension($id, $value, $critical = false, $replace = true, $path = null) - { - $extensions = &$this->_extensions($this->currentCert, $path, true); - - if (!is_array($extensions)) { - return false; - } - - $newext = array('extnId' => $id, 'critical' => $critical, 'extnValue' => $value); - - foreach ($extensions as $key => $value) { - if ($value['extnId'] == $id) { - if (!$replace) { - return false; - } - - $extensions[$key] = $newext; - return true; - } - } - - $extensions[] = $newext; - return true; - } - - /** - * Remove a certificate, CSR or CRL Extension - * - * @param string $id - * @access public - * @return bool - */ - function removeExtension($id) - { - return $this->_removeExtension($id); - } - - /** - * Get a certificate, CSR or CRL Extension - * - * Returns the extension if it exists and false if not - * - * @param string $id - * @param array $cert optional - * @access public - * @return mixed - */ - function getExtension($id, $cert = null) - { - return $this->_getExtension($id, $cert); - } - - /** - * Returns a list of all extensions in use in certificate, CSR or CRL - * - * @param array $cert optional - * @access public - * @return array - */ - function getExtensions($cert = null) - { - return $this->_getExtensions($cert); - } - - /** - * Set a certificate, CSR or CRL Extension - * - * @param string $id - * @param mixed $value - * @param bool $critical optional - * @param bool $replace optional - * @access public - * @return bool - */ - function setExtension($id, $value, $critical = false, $replace = true) - { - return $this->_setExtension($id, $value, $critical, $replace); - } - - /** - * Remove a CSR attribute. - * - * @param string $id - * @param int $disposition optional - * @access public - * @return bool - */ - function removeAttribute($id, $disposition = FILE_X509_ATTR_ALL) - { - $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes'); - - if (!is_array($attributes)) { - return false; - } - - $result = false; - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - case $disposition == FILE_X509_ATTR_REPLACE: - return false; - case $disposition >= $n: - $disposition -= $n; - break; - case $disposition == FILE_X509_ATTR_ALL: - case $n == 1: - unset($attributes[$key]); - $result = true; - break; - default: - unset($attributes[$key]['value'][$disposition]); - $attributes[$key]['value'] = array_values($attributes[$key]['value']); - $result = true; - break; - } - if ($result && $disposition != FILE_X509_ATTR_ALL) { - break; - } - } - } - - $attributes = array_values($attributes); - return $result; - } - - /** - * Get a CSR attribute - * - * Returns the attribute if it exists and false if not - * - * @param string $id - * @param int $disposition optional - * @param array $csr optional - * @access public - * @return mixed - */ - function getAttribute($id, $disposition = FILE_X509_ATTR_ALL, $csr = null) - { - if (empty($csr)) { - $csr = $this->currentCert; - } - - $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes'); - - if (!is_array($attributes)) { - return false; - } - - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - case $disposition == FILE_X509_ATTR_REPLACE: - return false; - case $disposition == FILE_X509_ATTR_ALL: - return $attribute['value']; - case $disposition >= $n: - $disposition -= $n; - break; - default: - return $attribute['value'][$disposition]; - } - } - } - - return false; - } - - /** - * Returns a list of all CSR attributes in use - * - * @param array $csr optional - * @access public - * @return array - */ - function getAttributes($csr = null) - { - if (empty($csr)) { - $csr = $this->currentCert; - } - - $attributes = $this->_subArray($csr, 'certificationRequestInfo/attributes'); - $attrs = array(); - - if (is_array($attributes)) { - foreach ($attributes as $attribute) { - $attrs[] = $attribute['type']; - } - } - - return $attrs; - } - - /** - * Set a CSR attribute - * - * @param string $id - * @param mixed $value - * @param bool $disposition optional - * @access public - * @return bool - */ - function setAttribute($id, $value, $disposition = FILE_X509_ATTR_ALL) - { - $attributes = &$this->_subArray($this->currentCert, 'certificationRequestInfo/attributes', true); - - if (!is_array($attributes)) { - return false; - } - - switch ($disposition) { - case FILE_X509_ATTR_REPLACE: - $disposition = FILE_X509_ATTR_APPEND; - case FILE_X509_ATTR_ALL: - $this->removeAttribute($id); - break; - } - - foreach ($attributes as $key => $attribute) { - if ($attribute['type'] == $id) { - $n = count($attribute['value']); - switch (true) { - case $disposition == FILE_X509_ATTR_APPEND: - $last = $key; - break; - case $disposition >= $n: - $disposition -= $n; - break; - default: - $attributes[$key]['value'][$disposition] = $value; - return true; - } - } - } - - switch (true) { - case $disposition >= 0: - return false; - case isset($last): - $attributes[$last]['value'][] = $value; - break; - default: - $attributes[] = array('type' => $id, 'value' => $disposition == FILE_X509_ATTR_ALL ? $value: array($value)); - break; - } - - return true; - } - - /** - * Sets the subject key identifier - * - * This is used by the id-ce-authorityKeyIdentifier and the id-ce-subjectKeyIdentifier extensions. - * - * @param string $value - * @access public - */ - function setKeyIdentifier($value) - { - if (empty($value)) { - unset($this->currentKeyIdentifier); - } else { - $this->currentKeyIdentifier = base64_encode($value); - } - } - - /** - * 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 - * - File_X509 object with public or private key defined - * - Certificate or CSR array - * - 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 strtolower(get_class($key)) == 'file_asn1_element': - // Assume the element is a bitstring-packed key. - $asn1 = new File_ASN1(); - $decoded = $asn1->decodeBER($key->element); - if (empty($decoded)) { - return false; - } - $raw = $asn1->asn1map($decoded[0], array('type' => FILE_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. - if (!class_exists('Crypt_RSA')) { - include_once 'Crypt/RSA.php'; - } - $key = new Crypt_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 strtolower(get_class($key)) == 'file_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.: Crypt_RSA). - $key = $key->getPublicKey(CRYPT_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. - if (!class_exists('Crypt_Hash')) { - include_once 'Crypt/Hash.php'; - } - $hash = new Crypt_Hash('sha1'); - $hash = $hash->hash($key); - - if ($method == 2) { - $hash = substr($hash, -8); - $hash[0] = chr((ord($hash[0]) & 0x0F) | 0x40); - } - - return $hash; - } - - /** - * Format a public key as appropriate - * - * @access private - * @return array - */ - function _formatSubjectPublicKey() - { - if (!isset($this->publicKey) || !is_object($this->publicKey)) { - return false; - } - - switch (strtolower(get_class($this->publicKey))) { - case 'crypt_rsa': - // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason. - // the former is a good example of how to do fuzzing on the public key - //return new File_ASN1_Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()))); - return array( - 'algorithm' => array('algorithm' => 'rsaEncryption'), - 'subjectPublicKey' => $this->publicKey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1) - ); - default: - return false; - } - } - - /** - * Set the domain name's which the cert is to be valid for - * - * @access public - * @return array - */ - function setDomain() - { - $this->domains = func_get_args(); - $this->removeDNProp('id-at-commonName'); - $this->setDNProp('id-at-commonName', $this->domains[0]); - } - - /** - * Set the IP Addresses's which the cert is to be valid for - * - * @access public - * @param string $ipAddress optional - */ - function setIPAddress() - { - $this->ipAddresses = func_get_args(); - /* - if (!isset($this->domains)) { - $this->removeDNProp('id-at-commonName'); - $this->setDNProp('id-at-commonName', $this->ipAddresses[0]); - } - */ - } - - /** - * Helper function to build domain array - * - * @access private - * @param string $domain - * @return array - */ - function _dnsName($domain) - { - return array('dNSName' => $domain); - } - - /** - * Helper function to build IP Address array - * - * (IPv6 is not currently supported) - * - * @access private - * @param string $address - * @return array - */ - function _iPAddress($address) - { - return array('iPAddress' => $address); - } - - /** - * Get the index of a revoked certificate. - * - * @param array $rclist - * @param string $serial - * @param bool $create optional - * @access private - * @return int|false - */ - function _revokedCertificate(&$rclist, $serial, $create = false) - { - $serial = new Math_BigInteger($serial); - - foreach ($rclist as $i => $rc) { - if (!($serial->compare($rc['userCertificate']))) { - return $i; - } - } - - if (!$create) { - return false; - } - - $i = count($rclist); - $rclist[] = array('userCertificate' => $serial, - 'revocationDate' => $this->_timeField(@date('D, d M Y H:i:s O'))); - return $i; - } - - /** - * Revoke a certificate. - * - * @param string $serial - * @param string $date optional - * @access public - * @return bool - */ - function revoke($serial, $date = null) - { - if (isset($this->currentCert['tbsCertList'])) { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { - if ($this->_revokedCertificate($rclist, $serial) === false) { // If not yet revoked - if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { - if (!empty($date)) { - $rclist[$i]['revocationDate'] = $this->_timeField($date); - } - - return true; - } - } - } - } - - return false; - } - - /** - * Unrevoke a certificate. - * - * @param string $serial - * @access public - * @return bool - */ - function unrevoke($serial) - { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - unset($rclist[$i]); - $rclist = array_values($rclist); - return true; - } - } - - return false; - } - - /** - * Get a revoked certificate. - * - * @param string $serial - * @access public - * @return mixed - */ - function getRevoked($serial) - { - if (is_array($rclist = $this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $rclist[$i]; - } - } - - return false; - } - - /** - * List revoked certificates - * - * @param array $crl optional - * @access public - * @return array - */ - function listRevoked($crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (!isset($crl['tbsCertList'])) { - return false; - } - - $result = array(); - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - foreach ($rclist as $rc) { - $result[] = $rc['userCertificate']->toString(); - } - } - - return $result; - } - - /** - * Remove a Revoked Certificate Extension - * - * @param string $serial - * @param string $id - * @access public - * @return bool - */ - function removeRevokedCertificateExtension($serial, $id) - { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_removeExtension($id, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Get a Revoked Certificate Extension - * - * Returns the extension if it exists and false if not - * - * @param string $serial - * @param string $id - * @param array $crl optional - * @access public - * @return mixed - */ - function getRevokedCertificateExtension($serial, $id, $crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_getExtension($id, $crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Returns a list of all extensions in use for a given revoked certificate - * - * @param string $serial - * @param array $crl optional - * @access public - * @return array - */ - function getRevokedCertificateExtensions($serial, $crl = null) - { - if (!isset($crl)) { - $crl = $this->currentCert; - } - - if (is_array($rclist = $this->_subArray($crl, 'tbsCertList/revokedCertificates'))) { - if (($i = $this->_revokedCertificate($rclist, $serial)) !== false) { - return $this->_getExtensions($crl, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - - return false; - } - - /** - * Set a Revoked Certificate Extension - * - * @param string $serial - * @param string $id - * @param mixed $value - * @param bool $critical optional - * @param bool $replace optional - * @access public - * @return bool - */ - function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true) - { - if (isset($this->currentCert['tbsCertList'])) { - if (is_array($rclist = &$this->_subArray($this->currentCert, 'tbsCertList/revokedCertificates', true))) { - if (($i = $this->_revokedCertificate($rclist, $serial, true)) !== false) { - return $this->_setExtension($id, $value, $critical, $replace, "tbsCertList/revokedCertificates/$i/crlEntryExtensions"); - } - } - } - - return false; - } - - /** - * Extract raw BER from Base64 encoding - * - * @access private - * @param string $str - * @return string - */ - function _extractBER($str) - { - /* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them - * above and beyond the ceritificate. - * ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line: - * - * Bag Attributes - * localKeyID: 01 00 00 00 - * subject=/O=organization/OU=org unit/CN=common name - * issuer=/O=organization/CN=common name - */ - $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1); - // remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff - $temp = preg_replace('#-+[^-]+-+#', '', $temp); - // remove new lines - $temp = str_replace(array("\r", "\n", ' '), '', $temp); - $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false; - return $temp != false ? $temp : $str; - } - - /** - * Returns the OID corresponding to a name - * - * What's returned in the associative array returned by loadX509() (or load*()) is either a name or an OID if - * no OID to name mapping is available. The problem with this is that what may be an unmapped OID in one version - * of phpseclib may not be unmapped in the next version, so apps that are looking at this OID may not be able - * to work from version to version. - * - * This method will return the OID if a name is passed to it and if no mapping is avialable it'll assume that - * what's being passed to it already is an OID and return that instead. A few examples. - * - * getOID('2.16.840.1.101.3.4.2.1') == '2.16.840.1.101.3.4.2.1' - * getOID('id-sha256') == '2.16.840.1.101.3.4.2.1' - * getOID('zzz') == 'zzz' - * - * @access public - * @return string - */ - function getOID($name) - { - static $reverseMap; - if (!isset($reverseMap)) { - $reverseMap = array_flip($this->oids); - } - return isset($reverseMap[$name]) ? $reverseMap[$name] : $name; - } -} |