/** * Save CSR request * * @param Array $csr * @access public * @return String */ function saveCSR($csr) { if (!is_array($csr) || !isset($csr['certificationRequestInfo'])) { return false; } switch ($csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm']) { case 'rsaEncryption': $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] = base64_encode("" . base64_decode(preg_replace('#-.+-|[\\r\\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))); } $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); $csr = $asn1->encodeDER($csr, $this->CertificationRequest); return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr)) . '-----END CERTIFICATE REQUEST-----'; }
/** * Get the Distinguished Name for a certificates subject * * @param Mixed $format optional * @param Array $dn optional * @access public * @return Boolean */ 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); return $asn1->encodeDER($dn, $this->Name); case FILE_X509_DN_OPENSSL: $dn = $this->getDN(FILE_X509_DN_STRING, $dn); if ($dn === false) { return false; } $attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE); $dn = array(); for ($i = 1; $i < count($attrs); $i += 2) { $prop = trim($attrs[$i], ', =/'); $value = $attrs[$i + 1]; if (!isset($dn[$prop])) { $dn[$prop] = $value; } else { $dn[$prop] = array_merge((array) $dn[$prop], array($value)); } } return $dn; 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. $asn1 = new File_ASN1(); $asn1->loadOIDs($this->oids); $filters = array(); $filters['value'] = array('type' => FILE_ASN1_TYPE_UTF8_STRING); $asn1->loadFilters($filters); $result = ''; foreach ($dn['rdnSequence'] as $rdn) { foreach ($rdn as &$attr) { 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')) { require_once 'Crypt/Hash.php'; } $hash = new Crypt_Hash('sha1'); $hash = $hash->hash($dn); extract(unpack('Vhash', $hash)); return strtolower(bin2hex(pack('N', $hash))); } // Defaut is to return a string. $start = true; $output = ''; $asn1 = new File_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; 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. } } $output .= $desc . $value; $start = false; } return $output; }
/** * Save a SPKAC CSR request * * @param Array $csr * @param Integer $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("" . 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: // case FILE_X509_FORMAT_PEM: default: // OpenSSL's implementation of SPKAC requires the SPKAC be // preceeded by SPKAC= and since there are pretty much // no other SPKAC decoders phpseclib will use that same format return 'SPKAC=' . base64_encode($spkac); } }
/** * Save X.509 certificate * * @param optional Array $cert * @access public * @return String */ function saveX509($cert) { if (!is_array($cert) || !isset($cert['tbsCertificate'])) { return false; } switch ($cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm']) { case 'rsaEncryption': $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] = base64_encode("" . base64_decode(preg_replace('#-.+-|[\\r\\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))); } $asn1 = new File_ASN1(); $asn1->loadOIDs($this->oids); $filters = array(); $filters['tbsCertificate']['signature']['parameters'] = $filters['tbsCertificate']['signature']['issuer']['rdnSequence']['value'] = $filters['tbsCertificate']['issuer']['rdnSequence']['value'] = $filters['tbsCertificate']['subject']['rdnSequence']['value'] = $filters['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = $filters['signatureAlgorithm']['parameters'] = $filters['authorityCertIssuer']['directoryName']['rdnSequence']['value'] = $filters['distributionPoint']['fullName']['directoryName']['rdnSequence']['value'] = $filters['directoryName']['rdnSequence']['value'] = array('type' => FILE_ASN1_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); if (isset($cert['tbsCertificate']['extensions'])) { $size = count($cert['tbsCertificate']['extensions']); for ($i = 0; $i < $size; $i++) { $id = $cert['tbsCertificate']['extensions'][$i]['extnId']; $value =& $cert['tbsCertificate']['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) . ""; $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', E_USER_NOTICE); unset($cert['tbsCertificate']['extensions'][$i]); } } else { $temp = $asn1->encodeDER($value, $map); $value = base64_encode($temp); } } } $cert = $asn1->encodeDER($cert, $this->Certificate); return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert)) . '-----END CERTIFICATE-----'; }