asp.net 5.0 https的雙向認證(windows和ubuntu)以及go的調用


前幾天搞go 的Grpc和http2的雙向認證。現在來搞搞。net core 里面是如何實現的

首先需要下載 OpenSSL http://slproweb.com/products/Win32OpenSSL.html 

windows

證書創建:

一、創建根證書

//生成key文件,輸入密碼:
openssl genrsa -des3 -out root.key
//生成請求證書文件,如果安裝路徑發生改變,可以通過在下面命令后面添加-config openssl.cfg來指明配置文件路徑
openssl req -new -key root.key -out root.csr  //生成一個10年期根證書 root.crt: openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey root.key -in root.csr -out root.crt //分別在客戶端或服務端安裝根證書,windows上安裝證書時,證書存儲可選擇“受信任的根證書頒發機構

二、創建服務端證書

//生成key文件,輸入密碼
openssl genrsa -des3 -out server.key 2048
//生成請求證書文件,如果安裝路徑發生改變
openssl req -new -key server.key -out server.csr
//用根證書生成一個10年期證書 server.crt:
openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in server.csr -out server.crt //生成.net core識別的證書文件server.pfx openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx

三、創建客戶端證書

//生成key文件,輸入密碼
openssl genrsa -des3 -out client.key 2048
//生成請求證書文件,如果安裝路徑發生改變
openssl req -new -key client.key -out client.csr
//用根證書生成一個10年期證書 client.crt:
openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in client.csr -out client.crt //生成.net core識別的證書文件client.pfx openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx

創建項目

接下來創建asp.net core web api項目,並把server.pfx添加到項目中,並設置屬性為“始終復制”,接着修改Program.cs下的CreateHostBuilder方法就可以: linux 上路徑變為 "cert/server.pfx“

 public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();

                    webBuilder.ConfigureKestrel(kerstrel =>
                    {
                        kerstrel.ConfigureHttpsDefaults(https =>
                        {
                            var serverPath = AppDomain.CurrentDomain.BaseDirectory + "cert\\server.pfx";
                            var serverCertificate = new X509Certificate2(serverPath, "123456789");
                            https.ServerCertificate = serverCertificate;
                            https.ClientCertificateMode = ClientCertificateMode.AllowCertificate;
                            https.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.None | SslProtocols.Tls11;
                            https.ClientCertificateValidation = (cer, chain, error) =>
                                       {
                                           return chain.Build(cer);
                                       };

                        });
                    });
                });

為了區分http和https請求,在WeatherForecastController中寫如下代碼:

 [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            var cer = HttpContext.Connection.ClientCertificate;
            //證書為空,返回過去的時間
            if (cer == null)
                   {
                return Enumerable.Range(1, 5).Select(index => new WeatherForecast
                {
                    Date = DateTime.Now.AddDays(-index),
                    TemperatureC = rng.Next(-20, 55),
                    Summary = Summaries[rng.Next(Summaries.Length)]
                })
                .ToArray();
            }
 
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }

創建客戶應用,.net core的控制台項目,把client.pfx添加到項目中,並設置屬性為“始終復制”,然后代碼如下

 static void Main(string[] args)
        {
            var handler = new HttpClientHandler()
            {
                SslProtocols = SslProtocols.Tls12,
                ClientCertificateOptions = ClientCertificateOption.Manual,
                ServerCertificateCustomValidationCallback = (message, cer, chain, errors) =>
                {
                    return chain.Build(cer);
                }
            };
            var path = AppDomain.CurrentDomain.BaseDirectory + "cert\\client.pfx";
            var crt = new X509Certificate2(path, "123456789");
            handler.ClientCertificates.Add(crt);

            var client = new HttpClient(handler);
            var url = "https://localhost:5001/WeatherForecast";
            var response = client.GetAsync(url).Result;
            Console.WriteLine(response.IsSuccessStatusCode);
            var back = response.Content.ReadAsStringAsync().Result;
            Console.WriteLine(back);
        }

結果如下圖:

Linux(Ubuntu環境安裝)

//參考 https://docs.microsoft.com/zh-cn/dotnet/core/install/linux-ubuntu

sudo apt update //
wget https://packages.microsoft.com/config/ubuntu/20.10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb

sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y dotnet-sdk-5.0

安裝證書:

//Ubuntu上CA證書的配置可以通過工具ca-certificates來方便的進行。該工具默認是隨Ubuntu安裝的,如果沒有可以通過下面的命令來安裝:
sudo apt-get install ca-certificates
//需要安裝CA證書我們只需要將其放在”/usr/share/ca-certificates”目錄或其子目錄下,ca-certificates工具就能自動掃描到。為了不與其它根證書混淆,我們創建一個子目錄名為”extra”:
sudo mkdir /usr/share/ca-certificates/extra
//然后將待安裝的證書拷貝到剛剛創建的目錄下:(注意這里的證書是.crt的擴展名)
sudo cp root.crt /usr/share/ca-certificates/extra/root.crt
//接下來讓ca-certificates工具幫我們安裝CA證書: 選擇”Yes”,我們能看到待安裝的CA證書已經被掃描到了,選中它(點空格鍵)然后選”OK”就行了。
sudo dpkg-reconfigure ca-certificates

運行結果:

 下載 https://download.csdn.net/download/dz45693/14012026  https://github.com/dz45693/dotnetHttpcert.git

備注:分別在客戶端或服務端安裝根證書,windows上安裝證書時,證書存儲可選擇“受信任的根證書頒發機構”(我就是沒有注意這一點搞了我1天多啊)

Go的調用

go需要的證書格式是pem, 我用上面的證書 搞成pem后面有些錯誤,然后嘗試讓C# 使用SAN的證書【證書生成請參考】,結果發現可以通過,然后生成C#的pfx文件

 openssl pkcs12 -export -in server.pem -inkey server.key -out server.pfx
openssl pkcs12 -export -in client.pem -inkey client.key -out client.pfx

main.go的代碼如下(代碼本來沒有難度, 關鍵是證書轉換):

package main
 
import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "time"
 
    "golang.org/x/net/http2"
)
 
func main() {
    clientCertFile := "client.pem"
    clientKeyFile := "client.key"
    caCertFile := "ca.pem"
    var cert tls.Certificate
    var err error
    if clientCertFile != "" && clientKeyFile != "" {
        cert, err = tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
        if err != nil {
            fmt.Println(err)
            log.Fatalf("Error creating x509 keypair from client cert file %s and client key file %s", clientCertFile, clientKeyFile)
        }
    }
    caCert, err := ioutil.ReadFile(caCertFile)
    if err != nil {
        fmt.Printf("Error opening cert file %s, Error: %s", caCertFile, err)
    }
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    t := &http2.Transport{
        TLSClientConfig: &tls.Config{
            Certificates: []tls.Certificate{cert},
            RootCAs:      caCertPool,
        },
    }
 
    client := http.Client{Transport: t, Timeout: 15 * time.Second}
    resp, err := client.Get("https://localhost:5001/WeatherForecast")
    if err != nil {
        fmt.Printf("Failed get: %s\r\n", err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Failed reading response body: %s\r\n", err)
    }
    fmt.Printf("Client Got response %d: %s %s\r\n", resp.StatusCode, resp.Proto, string(body))
 
}

運行結果 :

 

 

參考:

https://www.cnblogs.com/axzxs2001/p/10070562.html


免責聲明!

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



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