【PHP】用PHP自带的openssl生成证书,附带win版openssl命令

w132140 2018-08-04 09:20:31
账号很久以前就注册了,这是第一次发帖。
内容如题
流程如下:
1.首先需要一个openssl.cnf文件,一般PHP都有自带,路径d:\php\php7.0.10\extras\ssl\openssl.cnf
2.目录中需要一个tmp文件夹,自行创建
3.openssl.cnf的同级目录中需要一个demoCA文件夹(没有也可以)
图中选中的文件以及文件夹必须有

上代码:PHP接口(下面HTML中用到的sslApi.php)

<?php
if($_POST["type"]=="cert"){
// header('Content-Type: text/html; charset=utf-8');

//define("DIR","");//配置当前PHP程序目录
$dn = array(
"countryName" => $_POST["countryName"], //所在国家名称
"stateOrProvinceName" => $_POST["stateOrProvinceName"], //所在省份名称
"localityName" => $_POST["localityName"], //所在城市名称
"organizationName" => $_POST["organizationName"], //注册人姓名
"organizationalUnitName" => $_POST["organizationalUnitName"], //组织名称
"commonName" => $_POST["commonName"], //公共名称
"emailAddress" => $_POST["emailAddress"]?$_POST["emailAddress"]:"None"
//邮箱
);
// var_dump($dn);
$privkeypass = $_POST["pwd"]; //私钥密码
$numberofdays= $_POST["day"]; //有效时长
$config = array(
"digest_alg" => "sha256",
"private_key_bits" => 4096, //字节数 512 1024 2048 4096 等
"private_key_type" => OPENSSL_KEYTYPE_RSA, //加密类型
"config" => getcwd()."/openssl.cnf"
);
$res = openssl_pkey_new($config);
$cert=null;
$csr = openssl_csr_new($dn, $res,$config);//生成CSR
$jg["a1"]=openssl_pkey_export($res, $private_key,$privkeypass,$config);
$sscert = openssl_csr_sign($csr,$cert, $res, $numberofdays,$config);//用另一个证书签署 CSR (或者本身) 并且生成一个证书 $key为另一个crt证书的路径
$jg["a2"]=openssl_x509_export($sscert,$newCrtStr);
$jg["a3"]=openssl_csr_export($csr,$newCsr);
$newCsrFile = fopen("./tmp/newCsr.csr", "w");
$newKeyFile = fopen("./tmp/newKey.pem", "w");
$newCrtFile = fopen("./tmp/newCrt.crt", "w");
fwrite($newCsrFile, $newCsr);
fwrite($newKeyFile, $private_key);
fwrite($newCrtFile, $newCrtStr);
$jg["f1"]=fclose($newCsrFile);
$jg["f2"]=fclose($newKeyFile);
$jg["f3"]=fclose($newCrtFile);
$jg["code"]=1;
header('Content-type: application/json');
exit(json_encode($jg));
}else if($_POST["type"]=="p12"){
$private_key_pwd=$_POST["keyPwd"];
$p12_pwd=$_POST["p12Pwd"];
if(!isset($_FILES["crtFile"])){exit("文件超过规定大小");}
if(!isset($_FILES["keyFile"])){exit("文件超过规定大小");}
if($_FILES["crtFile"]["error"]!==0){exit("证书文件未选取");}
if($_FILES["keyFile"]["error"]!==0){exit("KEY文件未选取");}
$crtFile=$_FILES["crtFile"];
$keyFile=$_FILES["keyFile"];
if(isset($crtFile) && $crtFile["error"]==0){
$new_fileName="./tmp/up_crt.crt";
$crtFile_dir=move_uploaded_file($crtFile["tmp_name"],$new_fileName);
if($crtFile_dir){$crtFile_dir=$new_fileName;}
}
if(isset($keyFile) && $keyFile["error"]==0){
$new_fileName="./tmp/up_crtkey.pem";
$keyFile_dir=move_uploaded_file($keyFile["tmp_name"],$new_fileName);
if($keyFile_dir){$keyFile_dir=$new_fileName;}
}
$private_key=openssl_get_privatekey(file_get_contents($keyFile_dir),$private_key_pwd);
if($private_key){
openssl_pkcs12_export(file_get_contents($crtFile_dir),$p12Str,$private_key,$p12_pwd);
header('Content-Disposition: attachment; filename=P12证书文件.p12');
header('Content-Type: application/x-pkcs12');
header('Content-Length: '.strlen($p12Str));
echo $p12Str;
}else{
echo "私钥文件读取失败";
}
}else if($_POST["type"]=="p12Read"){
if(!isset($_FILES["p12File"])){exit("文件超过规定大小");}
$p12File=$_FILES["p12File"];
if(isset($p12File) && $p12File["error"]==0){
$new_fileName="./tmp/up_p12.p12";
$p12File_dir=move_uploaded_file($p12File["tmp_name"],$new_fileName);
if($p12File_dir){$p12File_dir=$new_fileName;}
$jg=openssl_pkcs12_read(file_get_contents($p12File_dir),$cert,$_POST["pwd"]);
if($jg){
header('Content-Type: text/html; charset=utf-8');
echo "操作成功,点击下载(或右键另存为)<br>";

echo "<a download='cert.crt' href='data:application/x-x509-ca-cert;base64,".base64_encode($cert["cert"])."'>cert.crt</a><br>";
echo "<a download='key.pem' href='data:text/plain;base64,".base64_encode($cert["pkey"])."'>key.pem</a>";
}else{
echo "P12文件读取失败";
}
}
}
exit();

html部分

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>openssl PHP版</title>
<script type="text/javascript" src="../jquery.min.js"></script>
</head>
<body>
<div>
<dl style="float: left;">
<td>生成证书和key文件</td>
<dd>国家名称:<input placeholder="CN" type="text" name="countryName"></dd>
<dd>省份名称:<input placeholder="Inner Mongolia" type="text" name="stateOrProvinceName"></dd>
<dd>城市名称:<input placeholder="Hohhot" type="text" name="localityName"></dd>
<dd>组织名称:<input placeholder="None" type="text" name="organizationalUnitName"></dd>
<dd>注册名称:<input placeholder="None" type="text" name="organizationName"></dd>
<dd>公共名称:<input placeholder="" type="text" name="commonName"></dd>
<dd>邮    箱:<input type="text" name="emailAddress"></dd>
<dd>有 效 期:
<select id="validity">
<option value="1">1年</option>
<option value="3">3年</option>
<option value="5">5年</option>
<option value="10">10年</option>
</select>
</dd>
<dd>密    码:<input placeholder="选填" type="text" name="pwd"></dd>
<dd><button onclick="new_cert('cert')">生成</button></dd>
</dl>
<dl style="float: left;">
<form action="./sslApi.php" method="POST" target="_blank" enctype="multipart/form-data">
<input type="hidden" name="type" value="p12">
<dt>根据证书及key生成客户端p12文件</dt>
<dd>证书(crt)文件:<input type="file" name="crtFile"></dd>
<dd>私钥(key)文件:<input type="file" name="keyFile"></dd>
<dd>私钥(key)密码:<input type="text" name="keyPwd"></dd>
<dd>新p12文件密码:<input type="text" placeholder="选填" name="p12Pwd"></dd>
<!-- <dd><button onclick="new_p12('p12')">生成P12文件</button></dd> -->
<dd><input type="submit" value="生成P12文件"></dd>
</form>
</dl>
<dl style="float: left;">
<form action="./sslApi.php" method="POST" target="_blank" enctype="multipart/form-data">
<input type="hidden" name="type" value="p12Read">
<dt>根据p12文件或pfx文件生成证书和私钥文件</dt>
<dd>P12文件:<input type="file" name="p12File"></dd>
<dd>密   码:<input type="text" name="pwd"></dd>
<dd><input type="submit" value="提交"></dd>
</form>
</dl>
<div style="clear: both;"></div>
</div>
<script type="text/javascript">
function new_cert(type){
var countryName = $("input[name=countryName]").val();
var stateOrProvinceName = $("input[name=stateOrProvinceName]").val();
var localityName = $("input[name=localityName]").val();
var organizationalUnitName = $("input[name=organizationalUnitName]").val();
var organizationName = $("input[name=organizationName]").val();
var commonName = $("input[name=commonName]").val();
var emailAddress = $("input[name=emailAddress]").val();
var pwd = $("input[name=pwd]").val();
var validity = $("#validity").val();
//这里有空判断,根据自己的需要修改
if(!commonName){alert("公共名称不能为空");return false;}
if(!countryName){countryName="CN";}
if(!stateOrProvinceName){stateOrProvinceName="Inner Mongolia";}
if(!localityName){localityName="Hohhot";}
if(!organizationalUnitName){organizationalUnitName="None";}
if(!organizationName){organizationName="None";}
$.ajax({
type:"post",
url:"./sslApi.php",
data:{
countryName:countryName,
stateOrProvinceName:stateOrProvinceName,
localityName:localityName,
organizationalUnitName:organizationalUnitName,
organizationName:organizationName,
commonName:commonName,
emailAddress:emailAddress,
day:(validity*365),
pwd:pwd,
type:type
},success:function (ret) {
if(ret.code==1){
alert("操作完成,存储在tmp文件夹中");
}
}
})
}

</script>
</body>
</html>
...全文
389 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
w132140 2018-08-04
  • 打赏
  • 举报
回复
附带一个openssl命令,自己整理的
【生成证书需要的相关内容】
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:ZJ
Locality Name (eg, city) []:HZ
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Some Ltd. Corp.
Organizational Unit Name (eg, section) []:Some Unit
Common Name (eg, YOUR name) []:Someone
Email Address []:some@email.com
 国家名称(2字母代码)(非盟):CN
 州或省名称(全名)[状态]:NMG
 地区名称(如城市)[]:HOHHOT
 组织名称(如公司)(互联网Widgits Pty Ltd):none
 组织单元名称(例如,部分)[]:none
 常见的名字(例如,你的名字)[]:link (在建立HTTPS证书时,这里填写域名)
 电子邮件地址[]:1550971762@qq.com
【重要说明】
WIN环境下,openssl会自己寻找openssl.cnf文件,但是文件并不存在 运行openssl之前先执行set OPENSSL_CONF=完整路径\openssl.cnf
我的
set OPENSSL_CONF=D:\Program Files\OpenSSL-Win32\bin\openssl.cnf

解决方法:在使用一下所有命令时在末尾加上-config ./openssl.cnf即可,./openssl.cnf为你的openssl.cnf文件路径

第一步,建立自定义CA,建立CA文件夹
产生的目录结构如下:
-- demoCA/
|-- index.txt
|-- newcerts/
|-- private/
`-- serial (可从openssl目录中复制出来)

【生成 CA 证书的 RSA 密钥对】
首先,我们要为 CA 建立 RSA 密钥对。打开终端,使用如下命令生成 RSA 密钥对:(这一步不要加-config ./openssl.cnf)
genrsa -des3 -out ./demoCA/private/cakey.pem 2048
然后为生成的CA 证书的 RSA 密钥对设置密码

【生成 CA 证书请求】【一】
为了获取一个 CA 根证书,我们需要先制作一份证书请求。先前生成的 CA 密钥对被用于对证书请求签名。
req -new -days 365 -key ./demoCA/private/cakey.pem -out careq.pem
其中-days 365 意为证书有效期为356天
然后输入【生成证书需要的相关内容(最上面)】

【对 CA 证书请求进行签名】【二】
在实际应用中,用户可以通过向知名 CA 递交证书请求来申请证书。但是在这里,我们需要建立的是一个根 CA ,只能由我们自己来对证书请求进行签名。所以我们让 OpenSSL 使用证书请求中附带的密钥对对该请求进行签名,也就是所谓的“ self sign ”
ca -selfsign -in careq.pem -out cacert.pem
其中-in careq.pem 用来指定 careq.pem 为证书请求文件。
过程:会有 两次询问,Y确认即可
【一步完成 CA 证书请求生成及签名】【以上的步骤一以及步骤二可以一次性完成,命令如下】
req -new -x509 -days 365 -key ./demoCA/private/cakey.pem -out ./demoCA/cacert.pem
其中-days 365 意为证书有效期为356天
然后输入【生成证书需要的相关内容(最上面)】

至此,我们便已成功建立了一个私有根 CA 。在这个过程中,我们获得了一份 CA 密钥对文件 ./demoCA/private/cakey.pem 以及一份由此密钥对签名的 CA 根证书文件 ./demoCA/cacert.pem ,得到的 CA 目录结构如下:
|-- careq.pem
`-- demoCA/
|-- cacert.pem
|-- index.txt
|-- index.txt.attr
|-- index.txt.old
|-- newcerts/
| `-- 01.pem
|-- private/
| `-- cakey.pem
|-- serial
`-- serial.old

注:如果在 CA 建立过程中跳过证书请求生成的步骤,则不会产生 careq.pem 文件。

【签发证书】下面我们就可以利用建立起来的 CA 进行证书签发了。
【生成用户证书 RSA 密钥对】
参照 CA 的 RSA 密钥对生成过程,使用如下命令生成新的密钥对(这一步不要加-config ./openssl.cnf)
genrsa -des3 -out userkey.pem
然后为生成的CA证书的 RSA 密钥对设置密码

【生成用户证书请求】
参照 CA 的证书请求生成过程,使用如下命令生成新的证书请求
req -new -days 365 -key userkey.pem -out userreq.pem
然后输入【生成证书需要的相关内容(最上面),注意国家、省、市、公司、单位必须与CA一致,否则无法签名】
其次是公司名称(选填)与密码
【签发用户证书】
现在,我们可以用先前建立的 CA 来对用户的证书请求进行签名来为用户签发证书了。使用如下命令:(如果需要增加“使用者备用名称(DNS)可以在命令后面加-extensions v3_req,并且确认openssl.cnf文件已经配置好,配置教程可以参考http://blog.51cto.com/colinzhouyj/1566438(感谢这位大神))
ca -in userreq.pem -out usercert.pem

证书用于网站https需要去除key文件口令
【去除文件口令】
输入 源key文件 输出的是不用密码的key文件
rsa -in C:\nginx\ssl\www.ats.com.key -out C:\nginx\ssl\www.ats.com.key.org
w132140 2018-08-04
  • 打赏
  • 举报
回复
图没上传成功再传一遍

21,886

社区成员

发帖
与我相关
我的任务
社区描述
从PHP安装配置,PHP入门,PHP基础到PHP应用
社区管理员
  • 基础编程社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧