gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
78.37k stars 8k forks source link

Unable to get certificate information on incoming https-request #3106

Open arer0008 opened 2 years ago

arer0008 commented 2 years ago

Description

I can't get information from the client certificate such as Organization and CommonName

How to reproduce

package main

import (
    "fmt"
    "net/http"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func Ping(c *gin.Context) {
    cert := c.Request.TLS.PeerCertificates // Returns an empty array
    fmt.Println(cert)
    c.JSON(http.StatusOK, gin.H{"payload": "Hello!"})
}

func main() {
    gin.SetMode(gin.ReleaseMode)
    r := gin.Default()
    r.Use(cors.Default())
    r.GET("/ping", Ping)
    r.RunTLS("0.0.0.0:8188", "cert.pem", "key.pem")
}

Expectations

An array with my certificates should be printed

Actual result

En empty array is printed

Environment

mohsalsaleem commented 2 years ago

If you read through the docs at https://pkg.go.dev/crypto/tls?utm_source=gopls#ConnectionState.PeerCertificates, it says

PeerCertificates are the parsed certificates sent by the peer, in the order in which they were sent... On the client side, it can't be empty. On the server side, it can be empty if Config.ClientAuth is not RequireAnyClientCert or RequireAndVerifyClientCert.

This means that, the Config.ClientAuth must be set to either of the mentioned values and the client must send the certs.

Below is a working example I've attached.

I've used mkcert to generate the cert and key.

mkcert 127.0.0.1

main.go

package main

import (
    "crypto/tls"
    "fmt"
    "net/http"

    "github.com/gin-contrib/cors"
    "github.com/gin-gonic/gin"
)

func Ping(c *gin.Context) {
    certs := c.Request.TLS.PeerCertificates 
    for _, v := range certs {
        fmt.Printf("v.Issuer: %v\n", v.Issuer)
    }
    c.JSON(http.StatusOK, gin.H{"payload": "Hello!"})
}

func main() {
    gin.SetMode(gin.ReleaseMode)
    r := gin.Default()
    r.Use(cors.Default())
    r.GET("/ping", Ping)
    tlsConfig := &tls.Config{
        ClientAuth: tls.RequireAnyClientCert,
    }

    s := http.Server{
        Addr:      "127.0.0.1:8188",
        Handler:   r,
        TLSConfig: tlsConfig,
    }
    s.ListenAndServeTLS("127.0.0.1.pem", "127.0.0.1-key.pem")
}

cURL command

curl -v \
--key 127.0.0.1-key.pem \
--cert 127.0.0.1.pem \
 https://127.0.0.1:8188/ping

Output

v.Issuer: CN=mkcert user@user-LT.laptop.local (user),OU=user@user-LT.laptop.local (user),O=mkcert development CA
v.Issuer: CN=mkcert user@user-LT.laptop.local (user),OU=user@user-LT.laptop.local (user),O=mkcert development CA
[GIN] 2022/04/01 - 11:27:36 | 200 |      94.016µs |       127.0.0.1 | GET      "/ping"