首页 文章资讯内容详情

golang证书认证通信

2026-06-01 2 花语

本文内容纲要:

-1.Golang中证书相关包 -2.认证过程 -3.单向认证 -4.双向认证 -5.跳过证书验证

1.Golang中证书相关包

crypto/tls实现tls1.2和tls1.3。

typeConfigstruct{

...... //Certificatescontainsoneormorecertificatechainstopresenttothe //othersideoftheconnection.Thefirstcertificatecompatiblewiththe //peersrequirementsisselectedautomatically. // //ServerconfigurationsmustsetoneofCertificates,GetCertificateor

//GetConfigForClient.Clientsdoingclient-authenticationmayseteither //CertificatesorGetClientCertificate. // //Note:iftherearemultipleCertificates,andtheydonthavethe //optionalfieldLeafset,certificateselectionwillincurasignificant //per-handshakeperformancecost. Certificates[]Certificate //RootCAsdefinesthesetofrootcertificateauthorities //thatclientsusewhenverifyingservercertificates. //IfRootCAsisnil,TLSusesthehostsrootCAset. RootCAs*x509.CertPool //ServerNameisusedtoverifythehostnameonthereturned //certificatesunlessInsecureSkipVerifyisgiven.Itisalsoincluded //intheclientshandshaketosupportvirtualhostingunlessitis //anIPaddress. ServerNamestring //ClientAuthdeterminestheserverspolicyfor //TLSClientAuthentication.ThedefaultisNoClientCert. ClientAuthClientAuthType //ClientCAsdefinesthesetofrootcertificateauthorities //thatserversuseifrequiredtoverifyaclientcertificate //bythepolicyinClientAuth. ClientCAs*x509.CertPool //InsecureSkipVerifycontrolswhetheraclientverifiesthe //serverscertificatechainandhostname. //IfInsecureSkipVerifyistrue,TLSacceptsanycertificate //presentedbytheserverandanyhostnameinthatcertificate. //Inthismode,TLSissusceptibletoman-in-the-middleattacks. //Thisshouldbeusedonlyfortesting. InsecureSkipVerifybool ...... }

LoadX509KeyPairreadsandparsesapublic/privatekeypairfromapairoffiles.

funcLoadX509KeyPair(certFile,keyFilestring)(Certificate,error)

crypot/x509解析X.509格式的密钥和证书。

typeCertPoolstruct{ //containsfilteredorunexportedfields }

CertPoolisasetofcertificates.

funcNewCertPool()*CertPool

NewCertPool返回一个空的CertPool。

funcSystemCertPool()(*CertPool,error)

SystemCertPoolreturnsacopyofthesystemcertpool.

func(s*CertPool)AppendCertsFromPEM(pemCerts[]byte)(okbool)

AppendCertsFromPEMattemptstoparseaseriesofPEMencodedcertificates.Itappendsanycertificatesfoundtosandreportswhetheranycertificatesweresuccessfullyparsed.

typeCertificatestruct{ Raw[]byte//CompleteASN.1DERcontent(certificate,signaturealgorithmandsignature). RawTBSCertificate[]byte//CertificatepartofrawASN.1DERcontent.RawSubjectPublicKeyInfo[]byte//DERencodedSubjectPublicKeyInfo. RawSubject[]byte//DERencodedSubject RawIssuer[]byte//DERencodedIssuer Signature[]byte SignatureAlgorithmSignatureAlgorithm PublicKeyAlgorithmPublicKeyAlgorithm PublicKeyinterface{} Versionint SerialNumber*big.Int Issuerpkix.Name Subjectpkix.Name NotBefore,NotAftertime.Time//Validitybounds. KeyUsageKeyUsage //ExtensionscontainsrawX.509extensions.Whenparsingcertificates, //thiscanbeusedtoextractnon-criticalextensionsthatarenot //parsedbythispackage.Whenmarshalingcertificates,theExtensions //fieldisignored,seeExtraExtensions. Extensions[]pkix.Extension//Go1.2 //ExtraExtensionscontainsextensionstobecopied,raw,intoany //marshaledcertificates.Valuesoverrideanyextensionsthatwould //otherwisebeproducedbasedontheotherfields.TheExtraExtensions //fieldisnotpopulatedwhenparsingcertificates,seeExtensions. ExtraExtensions[]pkix.Extension//Go1.2 //UnhandledCriticalExtensionscontainsalistofextensionIDsthat //werenot(fully)processedwhenparsing.Verifywillfailifthis //sliceisnon-empty,unlessverificationisdelegatedtoanOS //librarywhichunderstandsallthecriticalextensions. // //UserscanaccesstheseextensionsusingExtensionsandcanremove //elementsfromthissliceiftheybelievethattheyhavebeen //handled. UnhandledCriticalExtensions[]asn1.ObjectIdentifier//Go1.5 ExtKeyUsage[]ExtKeyUsage//Sequenceofextendedkeyusages. UnknownExtKeyUsage[]asn1.ObjectIdentifier//Encounteredextendedkeyusagesunknowntothispackage. //BasicConstraintsValidindicateswhetherIsCA,MaxPathLen, //andMaxPathLenZeroarevalid. BasicConstraintsValidbool IsCAbool //MaxPathLenandMaxPathLenZeroindicatethepresenceand //valueoftheBasicConstraints"pathLenConstraint". // //Whenparsingacertificate,apositivenon-zeroMaxPathLen //meansthatthefieldwasspecified,-1meansitwasunset, //andMaxPathLenZerobeingtruemeanthatthefieldwas //explicitlysettozero.ThecaseofMaxPathLen==0withMaxPathLenZero==false //shouldbetreatedequivalentto-1(unset). // //Whengeneratingacertificate,anunsetpathLenConstraint //canberequestedwitheitherMaxPathLen==-1orusingthe //zerovalueforbothMaxPathLenandMaxPathLenZero. MaxPathLenint//MaxPathLenZeroindicatesthatBasicConstraintsValid==true //andMaxPathLen==0shouldbeinterpretedasanactual //maximumpathlengthofzero.Otherwise,thatcombinationis //interpretedasMaxPathLennotbeingset. MaxPathLenZerobool//Go1.4 SubjectKeyId[]byte AuthorityKeyId[]byte //RFC5280,4.2.2.1(AuthorityInformationAccess) OCSPServer[]string//Go1.2 IssuingCertificateURL[]string//Go1.2 //SubjectAlternateNamevalues.(Notethatthesevaluesmaynotbevalid //ifinvalidvalueswerecontainedwithinaparsedcertificate.For //example,anelementofDNSNamesmaynotbeavalidDNSdomainname.)DNSNames[]string EmailAddresses[]string IPAddresses[]net.IP//Go1.1 URIs[]*url.URL//Go1.10 //Nameconstraints PermittedDNSDomainsCriticalbool//iftruethenthenameconstraintsaremarkedcritical. PermittedDNSDomains[]string ExcludedDNSDomains[]string//Go1.9 PermittedIPRanges[]*net.IPNet//Go1.10 ExcludedIPRanges[]*net.IPNet//Go1.10PermittedEmailAddresses[]string//Go1.10 ExcludedEmailAddresses[]string//Go1.10 PermittedURIDomains[]string//Go1.10 ExcludedURIDomains[]string//Go1.10 //CRLDistributionPoints CRLDistributionPoints[]string//Go1.2 PolicyIdentifiers[]asn1.ObjectIdentifier }

示例:

caCertPath:="cert/ca.crt" caCrt,err:=ioutil.ReadFile(caCertPath) iferr!=nil{ fmt.Println("ReadFileerr:",err) return } pool.AppendCertsFromPEM(caCrt) net/http提供HTTP的client和server实现。

客户端定制:ForcontroloverHTTPclientheaders,redirectpolicy等:

client:=&http.Client{ CheckRedirect:redirectPolicyFunc, Transport:tr, }

Transport定制:Forcontroloverproxies,TLSconfiguration,keep-alives,compression等:

tr:=&http.Transport{ MaxIdleConns:10, IdleConnTimeout:30*time.Second, DisableCompression:true, TLSClientConfig:&tls.Config{ RootCAs:pool, Certificates:[]tls.Certificate{clicrt} } } client:=&http.Client{Transport:tr} resp,err:=client.Get("https://example.com")

服务端定制:

s:=&http.Server{ Addr:":8080", Handler:myHandler, ReadTimeout:10*time.Second, WriteTimeout:10*time.Second, MaxHeaderBytes:1<<20, TLSConfig:&tls.Config{ ClientCAs:pool, ClientAuth:tls.RequireAndVerifyClientCert, } } //log.Fatal(s.ListenAndServe()) log.Fatal(s.ListenAndServe("server.crt","server.key"))

HTTPS监听

Filescontainingacertificateandmatchingprivatekeyfortheservermustbeprovided.

funcListenAndServeTLS(addr,certFile,keyFilestring,handlerHandler)error

ListenAndServeTLSlistensontheTCPnetworkaddresssrv.AddrandthencallsServeTLStohandlerequestsonincomingTLSconnections.AcceptedconnectionsareconfiguredtoenableTCPkeep-alives.

func(srv*Server)ListenAndServeTLS(certFile,keyFilestring)error

ListenAndServeTLSalwaysreturnsanon-nilerror.AfterShutdownorClose,thereturnederrorisErrServerClosed.Server需要定制时使用。

2.认证过程

单向认证过程:

客户点包含ca.crt,服务端包含server.key和server.crt。

客户端:客户端生成一个随机数random-client,传到服务器端;

服务端:服务器端接收消息之后,生成一个随机数random-server和包含公钥的证书,一起回馈给客户端;

客户端:客户端收到的东西原封不动,加上premastersecret(通过random-client、random-server经过一定算法生成的数据),再一次送给服务器端,这次传过去的东西是经过服务端的公钥进行加密后数据;

服务端:服务端经过私钥(server.key),进行解密,获取premastersecret(协商密钥过程);

此时客户端和服务器端都拥有了三个要素:random-client、random-server和premastersecret,安全通道已经建立,以后的交流都会校检上面的三个要素通过算法算出的sessionkey。

双向认证过程相当于客户端和服务端反过来再执行认证、加解密、协商一遍。

3.单向认证

单向认证只需要服务器端有证书即可。

CA****证书

opensslgenrsa-outca.key4096 opensslreq-x509-new-nodes-keyca.key-subj"/CN=wang.com"-days365-outca.crt

Server****证书

用CA证书签发server证书。

opensslgenrsa-outserver.key2048 opensslreq-new-keyserver.key-subj"/CN=server"-outserver.csr opensslx509-req-inserver.csr-CAca.crt-CAkeyca.key-set_serial01-outserver.crt-days365

Server.go

服务器监听在:https://server:8088,域名是server证书申请的CN。

单向认证时服务端只需要使用http.ListenAndServeTLS()或srv.ListenAndServeTLS()导入证书即可。一般情况下,不需要配置Server,直接采用默认的http.ListenAndServeTLS()。

packagemain import( "fmt" "net/http" "os" ) varAddrstring=":8088" funchandler(whttp.ResponseWriter,r*http.Request){ w.Write([]byte("Hello")) } funcmain(){ http.HandleFunc("/",handler) _,err:=os.Open("cert/server.crt") iferr!=nil{ fmt.Println("Cantopenserver.crt") panic(err) } fmt.Printf("listen...[%s]\n",Addr) err=http.ListenAndServeTLS(Addr,"cert/server.crt","cert/server.key",nil) iferr!=nil{ fmt.Println(err) } }

Client.go

需要提前将server添加到/etc/hosts中以便本地测试。

单向认证时client端需导入CA根证书,需要定制http.Transport。

Golang默认支持HTTP/2协议,只要使用TLS则默认启动HTTP/2特性,但对httpClient做一些定制化配置后,会覆盖掉http库的默认行为,导致开启HTTP/1.1。

packagemain import( "fmt" "crypto/tls" "crypto/x509" "flag" "io/ioutil" "log" "net/http" "golang.org/x/net/http2" ) varaddr=flag.String("addr","https://server:8088?numa=4&numb=6","connectto") varhttpVer=flag.Int("httpVer",2,"HTTPversion") funcmain(){ flag.Parse() client:=&http.Client{} caCert,err:=ioutil.ReadFile("cert/ca.crt") iferr!=nil{ log.Fatalf("Readingservercertificate:%s",err) } pool:=x509.NewCertPool() pool.AppendCertsFromPEM(caCert) tlsConfig:=&tls.Config{ RootCAs:pool, } switch*httpVer{ case1: client.Transport=&http.Transport{ TLSClientConfig:tlsConfig, } case2: client.Transport=&http2.Transport{ TLSClientConfig:tlsConfig, } } resp,err:=client.Get(*addr) iferr!=nil{ log.Fatalf("Failedget:%s",err) } deferresp.Body.Close() body,err:=ioutil.ReadAll(resp.Body) iferr!=nil{ log.Fatalf("Failedreadingresponsebody:%s",err) } fmt.Printf("Response%d:%s\nbody:%s\n",resp.StatusCode,resp.Proto,string(body)) }

Curl的-k参数可忽略证书验证:

$curl--cacert"cert/ca.crt"https://server:8088 Hi,Thisisanexampleofhttpsserviceingolang! $curl-khttps://server:8088 Hi,Thisisanexampleofhttpsserviceingolang! $curl-vhttps://server:8088 *RebuiltURLto:https://server:8088/ *Trying127.0.0.1... *Connectedtoserver(127.0.0.1)port8088(#0) *found133certificatesin/etc/ssl/certs/ca-certificates.crt *found403certificatesin/etc/ssl/certs *ALPN,offeringhttp/1.1 *SSLconnectionusingTLS1.2/ECDHE_RSA_AES_128_GCM_SHA256 *servercertificateverificationfailed.CAfile:/etc/ssl/certs/ca-certificates.crtCRLfile:none *Closingconnection0

如果/CN使用IP地址,就会报如下类似错误:

Gethttps://10.183.47.206:8081:x509:cannotvalidatecertificatefor10.183.47.206becauseitdoesntcontainanyIPSANs

Client测试

$gorunclient.go Response200:HTTP/2.0 body:Hello $gorunclient.go-httpVer=1 Response200:HTTP/1.1 body:Hello

HTTP/1.1非加密(10数据帧)

HTTP/1.1单向认证(17数据帧)

HTTP/2单向认证(22数据帧)

4.双向认证

双向认证要求客户端和服务端都要有证书,且都用CA证书验证对端证书。

Client****证书

用CA证书签发client证书,而非server证书签发。

注意生成client端证书的时候,要多添加一个字段,golang的server端认证程序会对这个字段进行认证:

opensslgenrsa-outclient.key2048 opensslreq-new-keyclient.key-subj"/CN=client"-outclient.csr echoextendedKeyUsage=clientAuth>extfile.cnf opensslx509-req-inclient.csr-CAca.crt-CAkeyca.key-set_serial02-extfileextfile.cnf-outclient.crt-days365

Server.go

双向认证时需定制http.Server,增加CA证书等。

定制的http.Server的Handler是一个interface,需要实现ServeHTTP()接口函数;

加载服务端的公钥和私钥用于解密客户端发送过来的随机字符;

加载CA证书是为了验证客户端的证书是否合格;

packagemain import( "fmt" "net/http" "io/ioutil" "crypto/tls" "crypto/x509" ) typemyhandlerstruct{ } func(h*myhandler)ServeHTTP(whttp.ResponseWriter,r*http.Request){ fmt.Fprintf(w, "Hi,Thisisanexampleofhttpsserviceingolang!\n") } funcmain(){ pool:=x509.NewCertPool() caCertPath:="cert/ca.crt" caCrt,err:=ioutil.ReadFile(caCertPath) iferr!=nil{ fmt.Println("ReadFileerr:",err) return } pool.AppendCertsFromPEM(caCrt) s:=&http.Server{ Addr:":8088", Handler:&myhandler{}, TLSConfig:&tls.Config{ ClientCAs:pool, ClientAuth:tls.RequireAndVerifyClientCert, }, } fmt.Println("listen...") err=s.ListenAndServeTLS("cert/server.crt","cert/server.key") iferr!=nil{ fmt.Println(err) } }

Client.go

Client需要定制http.Transport以加载客户端证书和CA证书。

Client的证书需要tls.LoadX509KeyPair()导入。

packagemain import( "fmt" "io/ioutil" "net/http" "crypto/tls" "crypto/x509" "golang.org/x/net/http2" ) funcmain(){ //x509.Certificate pool:=x509.NewCertPool() caCertPath:="cert/ca.crt" caCrt,err:=ioutil.ReadFile(caCertPath) iferr!=nil{ fmt.Println("ReadFileerr:",err) return } pool.AppendCertsFromPEM(caCrt) cliCrt,err:=tls.LoadX509KeyPair("cert/client.crt","cert/client.key") iferr!=nil{ fmt.Println("LoadX509keypairerr:",err) return } //tr:=&http2.Transport{//http2协议 tr:=&http.Transport{//http1.1协议 TLSClientConfig:&tls.Config{ RootCAs:pool, Certificates:[]tls.Certificate{cliCrt}, }, } client:=&http.Client{Transport:tr} //resp,err:=client.Get("https://localhost:8088") resp,err:=client.Get("https://server:8088") iferr!=nil{ fmt.Println("httpgeterror:",err) panic(err) } body,_:=ioutil.ReadAll(resp.Body) fmt.Println(string(body)) fmt.Println(resp.Status) }

Curl验证

$curl--cacertcert/ca.crt--certcert/client.crt--keycert/client.keyhttps://server:8088 Hi,Thisisanexampleofhttpsserviceingolang!

Client测试

$gorundul_client.go Hi,Thisisanexampleofhttpsserviceingolang 200OK

HTTP/1.1双向认证(19数据帧)

HTTP/2双向认证(24数据帧)

5.跳过证书验证

POSTMAN或curl中都可以跳过单向证书验证,golang也可以滴。

tr:=&http.Transport{ TLSClientConfig:&tls.Config{InsecureSkipVerify:true}, } client:=&http.Client{Transport:tr}

参考:

Golang之双向认证简书

https原理以及golang基本实现

Go语言的http/2服务器功能及客户端使用

gRPC+gRPCGateway能不能不用证书?net/http2必须使用TLS交互;

“h2c”标识允许通过明文TCP运行HTTP/2的协议,此标识符用于HTTP/1.1升级标头字段以及标识HTTP/2overTCP。

通过GoLang全面了解HTTPS

Golang设置https访问,以及http如何重定向到https

本文内容总结:1.Golang中证书相关包,2.认证过程,3.单向认证,4.双向认证,5.跳过证书验证,

原文链接:https://www.cnblogs.com/embedded-linux/p/12585854.html