生成線上用https證書,支持通配符和多域名,初學Let’s Encrypt用於IIS,純本地手動


自簡書發布的上篇《生成本地測試用https證書,支持通配符和多域名,初學OpenSSL》以來,本地測試用https用的妥妥的。

線上一直用的騰訊雲的免費證書(每個域名都要一個證書(滑稽),今天線上用的通配符證書也搞定了,實現了一個證書包含多個域名(多個泛域名)。

2019-10-8 更新:添加對gethttpsforfree網頁中所有RSA簽名進行自動簽名,提供的自動簽名代碼在下面。

今年(2018)年初Let’s Encrypt已開放了通配符證書的申請《Wildcard Certificates Coming January 2018》,目前只支持通過dns解析進行驗證。沒有通配符的證書時在心里感覺用起來會很累,一直沒有去嘗試。以前AlphaSSL的通配符證書倒是可以免費申請,assl.loovit.net都已經跳轉到別的地方了。現在可以勇敢的去用Let’s Encrypt的通配符證書了。

官方並沒有簡單易用的客戶端

申請環境:本地(線上不亂搞),win7+Win32OpenSSL

Let’s Encrypt提供的客戶端列表包括開源實現《ACME Client Implementations》,電腦上能裝上的基本上都試了一下(捆綁生產環境的軟件不鳥),好幾個依賴高版本的.Net(勉為其難的裝了一下),始終沒搞懂怎么耍,入門到放棄。然后用C#調用了一個封裝好的接口試了一下,目測工作量也不小,入門到放棄。

Let’s Encrypt 使用吐槽》這里面說的比較贊同的一點這才是你真正需要的 acme-client ,只干申請證書這一件事的腳本。哈哈,其實發現申請證書只是簡單的調用幾個api.letsencrypt.orgRESTful接口,並且都含有響應頭Access-Control-Allow-Origin:*,就不去研究他們的文檔了,因為翻了一般官網,並沒有發現哪里有這種直接了當的文檔。

Let’s Encrypt提供的網頁客戶端列表中的Get HTTPS for free https://gethttpsforfree.com/就是直接使用的接口,這個網站聲稱This website is static, so it can be saved and loaded locally. Just right-click and "Save Page As.."! 查看代碼確實是一個靜態網站。其他幾個網頁客戶端也稍微試了一下,有些要注冊還主動幫你管理證書(不鳥)。其實一個靜態網頁也能夠實現證書的申請,還不用下載安裝各種環境,比較靠譜。

使用Get HTTPS for free申請證書

地址https://gethttpsforfree.com/ 這個頁面使用起來很方便,因為該提示的地方都有提示,按照提示做沒有壓力,順利申請到了兩個域名合在一起的證書。

主要要手動做的事情:

  1. 創建兩個秘鑰,一個賬戶秘鑰,一個域名證書秘鑰(2048位,這個網站寫4096位感覺有點大,百度和Let’s Encrypt都是2048位)
  2. 創建證書申請請求
  3. 多次進行文本內容簽名(用賬戶秘鑰)

*. 申請好的證書制作成pfx文件導入IIS (我用IIS是要這一步的)

這些步驟都可以用腳本去處理,點一下->復制粘貼,手動也不比自動差(其實也沒有便捷的全自動,dns驗證還是要手動寫入TXT記錄)

使用到的腳本

下面這些文件全部是在同一個文件夾里面: 1.創建秘鑰.cmd,2.生成請求.ini,2.生成請求.cmd,3.簽名.cmd,3.簽名.txt,4.導出.cmd

文件名:1.創建秘鑰.cmd

@echo off

set /p isSet=創建秘鑰會覆蓋現有秘鑰,確定要創建嗎?(y)
if not "%isSet%"=="y" goto end

echo 創建賬戶秘鑰
openssl genrsa -out key.account.private 2048
openssl rsa -in key.account.private -pubout -out key.account.public

echo 創建證書秘鑰
openssl genrsa -out key.domain.key 2048

:end
echo 結束
pause

文件名:2.生成請求.ini 這個文件是OpenSSL安裝目錄中的配置文件,copy過來改一下名字就行了,然后在文件結尾添加下面內容,域名自己加(泛解析的要把一級域名加上,不加他們會不會自動加不知道,目測不會自動加)

[ ext ]
subjectAltName = @dns

[ dns ]
DNS.1 = baidu1.com
DNS.2 = *.baidu1.com
DNS.3 = baidu2.com
DNS.4 = *.baidu2.com

文件名:2.生成請求.cmd

@echo off

set /p isSet=需要先配置域名列表"2.生成請求.ini",配置好了嗎?(y)
if not "%isSet%"=="y" goto end

echo 生成請求
openssl req -new -sha256 -key key.domain.key -out domain.csr -subj "/" -reqexts ext -config 2.生成請求.ini

:end
echo 結束
pause

文件名:3.簽名.cmd

@echo off

set /p isSet=需要先寫入"3.簽名.txt",寫好了嗎?(y)
if not "%isSet%"=="y" goto end

openssl dgst -sha256 -hex -sign key.account.private 3.簽名.txt

:end
echo 結束
pause

文件名:3.簽名.txt 這個文件是一個空文件,到時候有需要簽名的數據復制進來運行一下簽名.cmd就能快速獲得簽名。

文件名:4.導出.cmd

@echo off

echo 導出pfx,請輸入密碼1
pause
openssl pkcs12 -export -out domain.pfx -inkey key.domain.key -in domain.crt

:end
echo 結束
pause

申請制作過程

  1. 所有文件准備好后(尤其是2.生成請求.ini把域名配置好),直接運行1.創建秘鑰.cmd,然后直接運行2.生成請求.cmd
  2. 把生成的key.account.public填入網頁Account Public Key中。
  3. 把生成的domain.csr填入網頁Certificate Signing Request中。
  4. 根據網頁提示簽名請求,每次簽名的時候:把文本復制到3.簽名.txt(只要引號里面的文本內容,其他內容刪除),然后運行3.簽名.cmd得到簽名,把RSA-SHA256(3.簽名.txt)= XXXXX復制到網頁對應位置。
  5. 根據提示設置域名dns TXT解析,並完成驗證。
  6. 把最后一步生成的證書內容全部復制到新建的文件domain.crt中,域名證書就獲取成功啦。
  7. 額外的生成IIS用的pfx文件,運行一下4.導出.cmd設置一下密碼就行了,我提示輸入1作為密碼,是因為我懶(滑稽。

秀一波

證書域名 有效期 涉及到的文件

自動簽名

我使用了 fszlin/certes 來編寫了一個C#客戶端用來申請多域名證書,但經常操作到最后這個庫老是拋出申請錯誤信息,無奈每次手動用gethttpsforfree都能一次性完成申請。所以我就准備丟棄certes,僅僅使用gethttpsforfree。

但gethttpsforfree每次簽名最繁瑣的就是RSA簽名部分,復制來復制去,由於前段時間在我的H5錄音庫xiangyuecn/Recorder內實現了一個RSA簽名功能,因此直接拿過來給gethttpsforfree安裝上了自動簽名功能。

我給gethttpsforfree的github把這個功能提交了一個issue(他們家關閉了wiki),作者就來了一句SPAM。哈哈哈,自己好用就好,該做的我都做了,結果我才不管。https://github.com/diafygi/gethttpsforfree/issues/164 里面有詳細的自動簽名介紹。

自動簽名操作步驟:

  1. 打開 https://gethttpsforfree.com/頁面。
  2. 復制下面的代碼到瀏覽器控制台里面執行。
  3. 按頁面中的正常流程操作,填寫好私鑰,中途所有簽名操作都會自動完成。
(function(){

var privateSign=function(txt){
    //Signature
    try{
        var key=document.querySelector(".privateSignKey").value.replace(/-+.+?PRIVATE.+?-+|\s/g,"");
        var byts=Base64.decode(key);
        var asn1=ASN1.decode(byts);
        if(asn1.sub.length<9){//PKCS#8
            asn1=asn1.sub[2].sub[0];
        };
        var get=function(n){
            var item=asn1.sub[n];
            var start = item.stream.pos+item.header;
            var end = item.stream.pos+item.header+item.length;
            var hex = item.stream.hexDump(start, end);
            hex=hex.replace(/\s/g,"");
            hex=hex.replace(/^00/g,"");//type=02 INTEGER:Remove the highest bit-filled 0x00
            return RSA.HexToB64(hex);
        };
        var n=get(1);
        var e=get(2);
        var d=get(3);
        
        var rsa=RSA(n,e,d);
        var sign=rsa.sign(txt,"SHA256");
        if(!rsa.verify(txt,sign,"SHA256")){
            alert("private key seems to be wrong!");
            return "";
        };
        return RSA.B64ToHex(sign);
    }catch(e){
        console.error(e);
        alert("private key parse error!");
        return "";
    }
};

var install=function(){
    HTMLInputElement.prototype._setAttribute=HTMLInputElement.prototype.setAttribute;
    HTMLInputElement.prototype.setAttribute=function(k,v){
        var This=this;
        This._setAttribute.apply(This,arguments);
        
        if(!(k=="placeholder"&&v==RESULT_PLACEHOLDER)){
            return;
        };
        var signExec=function(){
            var find=This.parentNode.querySelectorAll("input");
            var arr=[];
            for(var i=0;i<find.length;i++){
                if(find[i].value.indexOf("openssl")+1){
                    arr.push(find[i]);
                };
            };
            if(arr.length!=1){
                alert("no input box for signature was found!");
                return;
            };
            This.value=privateSign(/"(.+)"/.exec(arr[0].value)[1]);
        };
        
        setTimeout(signExec,100);
        //blur exec
        This._setAttribute(k,"blur retry autofill sign. "+v);
        if(!This.isBindSignExec){
            This.isBindSignExec=true;
            This.addEventListener("blur",function(){
                if(This.value==""){
                    signExec();
                };
            });
        };
    };
    
    var div=document.createElement("div");
    div.innerHTML=`
        <div class="field">
            <div style="color:#0b1">Account Privete Key (RSA PKCS#1 or PKCS#8) (It's just for signature!):</div>
            <textarea class="privateSignKey" placeholder="-----BEGIN RSA PRIVATE KEY----- OR -----BEGIN PRIVATE KEY----- ..."></textarea>
        </div>
    `;
    validate_account.appendChild(div);
};

var script=document.createElement("script");
script.src="https://xiangyuecn.github.io/Recorder/assets/ztest-rsa.js";
script.onload=function(){
    setTimeout(function(){
        install();
    },1000);//emmm... doc was ready
};
document.querySelector("head").appendChild(script);

})();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM