x509是证书规范,公钥证书,只有公钥
证书签名申请CSR
/**
* @description: 证书签名申请,
* 生成证书前需要先生成CSR文件并提交给证书颁发机构(CA)
*/
class CSR
{
/**
* @description: csr可以是file://path/to/csr格式指定的PEM编码的CSR文件路径或是csr字符串或openssl_csr_new生成的资源
* @var mixed
*/
public static $csr;
/**
* @description: 证书中使用的专有名称或主题字段
* @var array
*/
public static $dn = [
'countryName' => 'CN', // 国家(2个字母代码)
'stateOrProvinceName' => 'China', // 国家或省名
'localityName' => 'China', // 地名(城市)
'organizationName' => 'ORG', // 组织名,ORG为有限公司
'organizationalUnitName' => 'ORG', // 组织单元名称
'commonName' => 'xxx.com', // 域名
'emailAddress' => 'my@163.com', // 邮件地址
];
/**
* @description: 摘要算法或签名哈希算法,openssl_get_md_methods()之一
* @var string
*/
private static $_digest_alg = 'sha256';
/**
* @description: openssl配置文件地址
* windows中php安装目录下存在此文件,但是php不能自动读取,有两种解决方法,
* 1、查看phpinfo中openssl.cnf的位置,将openssl.cnf挪到查询到的位置;
* 2、配置option中的config参数为指定的路径
* @var array
*/
private static $_config = 'C:/usr/local/ssl/openssl.cnf';
/**
* @description: 生成证书所需的CSR
* @param resource $privkey 私钥资源,该密钥的相应公共部分将用于签署CSR
* @param bool $notext 输出冗余度,false时输出内容附加人类可读信息(包括主体、版本等等)
* @return string
*/
public static function csrGen($privkey, $notext = true): string
{
// 初始化请求的配置
$configargs = [
'config' => static::$_config,
'digest_alg' => static::$_digest_alg
];
// 为CSR指定额外的配置选项
$extraattribs = [] ?: null;
static::$csr = openssl_csr_new(static::$dn, $privkey, $configargs, $extraattribs);
if (!static::$csr) {
throw new \Exception('csr资源生成错误');
}
openssl_csr_export(static::$csr, $out, $notext);
return $out;
}
/**
* @description: 获取csr中专有名称信息的主题,其中包含了通用名称(CN),机构名称(O),国家名(C)等字段
* @param {*}
* @return array
*/
public static function getCsrSubject(): array
{
static::_vertiy();
// true返回短名称索引
return openssl_csr_get_subject(static::$csr, true);
}
/**
* @description: 从csr中获取公钥资源
* @param {*}
* @return mixed 失败返回false,成功返回resource
*/
public static function csrGetPublicKey()
{
static::_vertiy();
return openssl_csr_get_public_key(static::$csr);
}
/**
* @description: 将csr保存在文件中
* @param string $outfilename 文件路径
* @param bool $notext 输出冗余度,false时输出内容附加人类可读信息(包括主体、版本等等)
* @return bool
*/
public static function csrOutFile($outfilename, $notext = true): bool
{
static::_vertiy();
return openssl_csr_export_to_file(static::$csr, $outfilename, $notext);
}
/**
* @description: 验证csr资源是否存在
* @param {*}
* @return void
*/
private static function _vertiy(): void
{
if (!static::$csr) {
throw new \Exception('请先生成/设置csr资源');
}
}
/**
* @description: 获取openSSL库的错误,错误消息已被队列化,可以查询到多条错误信息,最后一个是最近的一个错误。
* @param {*}
* @return {*}
*/
public static function errors(): array
{
$result = [];
while ($data = openssl_error_string() !== false) {
$result[] = $data;
}
return $result;
}
}
X509证书类
/**
* @description: 证书
*/
class Certificate
{
/**
* @description: x509证书资源
* @var resource
*/
public static $cert;
/**
* @description: 摘要算法或签名哈希算法,openssl_get_md_methods()之一
* @var string
*/
private static $_digest_alg = 'sha256';
/**
* @description: openssl配置文件地址
* windows中php安装目录下存在此文件,但是php不能自动读取,有两种解决方法,
* 1、查看phpinfo中openssl.cnf的位置,将openssl.cnf挪到查询到的位置;
* 2、配置option中的config参数为指定的路径
* @var array
*/
private static $_config = 'C:/usr/local/ssl/openssl.cnf';
/**
* @description: 从给定的CSR生成一个x509证书资源;用另一个证书签署 CSR (或者本身) 并且生成一个证书
* @param mixed $csr csr资源或字符串
* @param mixed $privkey 私钥,可以为字符串/资源,私钥资源,该密钥的相应公共部分将用于签署CSR
* @param int $days 证书有效时长
* @param mixed $cacert 生成的证书将由cacert证书签名。 如果cacert为 null, 生成的证书将是自签名证书
* @param string $serial 可选的发行证书编号。如果没有指定默认值为0
* @return void
*/
public static function GenX509($csr, $privkey, $days = 365, $cacert = null, $serial = '0'): void
{
$configargs = [
'config' => static::$_config,
'digest_alg' => static::$_digest_alg
];
static::$cert = openssl_csr_sign($csr, $cacert, $privkey, $days, $configargs, $serial);
if (!static::$cert) {
throw new \Exception('证书生成错误');
}
}
/**
* @description: 从证书文件中获取证书资源
* @param string $certdata 包含PEM编码(-----BEGIN CERTIFICATE----- 开头)的证书文件地址
* @return void
*/
public static function getCertifResource($certdata): void
{
static::$cert = openssl_x509_read('file://' . $certdata);
}
/**
* @description: 获取证书主题名称、发行方名称、目的、有效日期等字段
* @param bool $shortnames true返回短名称索引
* @return array
*/
public static function getCertifSubject($shortnames = true): array
{
static::_vertiy();
return openssl_x509_parse(static::$cert, $shortnames);
}
/**
* @description: 验证证书签名是否由公钥所对应的私钥签名,php7.4版本以上可用
* @param string $publicKey PEM格式的公钥
* @return int 1、正确 0、不正确 -1、错误
*/
public static function certifSignVerify($publicKey): int
{
static::_vertiy();
return openssl_x509_verify(static::$cert, $publicKey);
}
/**
* @description: 获取证书字符串
* @param bool $notext 输出冗余度,false时输出内容附加人类可读信息
* @return {*}
*/
public static function certData($notext = true): string
{
static::_vertiy();
openssl_x509_export(static::$cert, $output, $notext);
return $output;
}
/**
* @description: 将证书保存在文件中
* @param string $outfilename 文件路径
* @param bool $notext 输出冗余度,false时输出内容附加人类可读信息
* @return void
*/
public static function certOutFile($outfilename, $notext = true): void
{
static::_vertiy();
openssl_x509_export_to_file(static::$cert, $outfilename, $notext);
}
/**
* @description: 释放证书资源
* @param {*}
* @return void
*/
public static function freeCert(): void
{
static::_vertiy();
openssl_x509_free(static::$cert);
}
/**
* @description: 验证私钥是否属于证书,比较了和密钥匹配的公共材料(比如,RSA密钥的指数和模量)和/或密钥参数(比如,EC密钥的参数)。
* @param mixed $key 私钥资源,私钥字符串
* @return bool
*/
public static function verifyCertKey($key): bool
{
static::_vertiy();
return openssl_x509_check_private_key(static::$cert, $key);
}
/**
* @description: 计算证书摘要
* @param string $hash_algorithm 摘要算法,openssl_get_md_methods()算法之一
* @param bool $raw_output true输出原始二进制数据。false输出小写的16进制字符串。
* @return string
*/
public static function certifDigest($hash_algorithm = 'sha256', $raw_output = false): string
{
static::_vertiy();
return openssl_x509_fingerprint(static::$cert, $hash_algorithm, $raw_output);
}
/**
* @description: 验证证书是否具有指定用途
* @param int $purpose 用途,只能指定一个字段
* X509_PURPOSE_SSL_CLIENT SSL连接的客户端
* X509_PURPOSE_SSL_SERVER SSL连接的服务器端
* X509_PURPOSE_NS_SSL_SERVER Netscape SSL服务器
* X509_PURPOSE_SMIME_SIGN 签名 S/MIME 邮件
* X509_PURPOSE_SMIME_ENCRYPT 加密 S/MIME 邮件
* X509_PURPOSE_CRL_SIGN 签名证书撤销列表(CRL)
* X509_PURPOSE_ANY 任何目的
* @param bool $cainfo 包含可信CA文件的文件夹和文件名的数组,用于验证签名/认证
* @return mixed true、false -1、发生错误
*/
public static function certifEffect($purpose, $cainfo = []):int
{
static::_vertiy();
return openssl_x509_checkpurpose(static::$cert, $purpose, $cainfo);
}
/**
* @description: 查找本地可用SSL证书的位置
* @param {*}
* @return array
*/
public static function SSLlocaltion(): array
{
return openssl_get_cert_locations();
}
/**
* @description: 验证证书资源是否存在
* @param {*}
* @return void
*/
private static function _vertiy(): void
{
if (!static::$cert) {
throw new \Exception('请先生成/设置证书资源');
}
}
/**
* @description: 获取openSSL库的错误,错误消息已被队列化,可以查询到多条错误信息,最后一个是最近的一个错误。
* @param {*}
* @return {*}
*/
public static function errors(): array
{
$result = [];
while ($data = openssl_error_string() !== false) {
$result[] = $data;
}
return $result;
}
}
生成私钥资源:SecretKey类
$path = 'C:\Users\Administrator\Desktop\12\\';
SecretKey::genPrivateKey();
SecretKey::privateKeyOutFile($path . 'pkey.key');
CSR::csrGen(SecretKey::$privateKey);
CSR::csrOutFile($path . 'csr.csr');
Certificate::GenX509(CSR::$csr, SecretKey::$privateKey);
var_dump(Certificate::certData());
Certificate::certOutFile($path . 'cert.cer');