I want to use TLS mutual authentication to authenticate a client on a API made in go. I've created a certificate authority, and let's say Bob has a key pair he wants to use with the client. Bob created a certificate request and want me to validate his certificate in order to be authorized and authenticated on the API.
I've used this to create my Certificate Authority :
openssl genrsa -aes256 -out ca.key 4096
openssl req -new -x509 -sha256 -days 730 -key ca.key -out ca.crt
Bob used this to create his certificate and certificate request :
openssl genrsa -out bob.key 4096
openssl req -new -key bob.key -out bob.csr
I want to achive this, but in go :
openssl x509 -req -days 365 -sha256 -in bob.csr -CA ca.crt -CAkey ca.key -set_serial 3 -out bob.crt
For now, with theses commands, Bob can create a TLS connection to my API which use this tls.Config :
func createTLSConfig(certFile string, keyFile string, clientCAFilepath string) (config *tls.Config, err error) {
cer, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
return nil, err
}
clientCAFile, err := ioutil.ReadFile(clientCAFilepath)
if err != nil {
return nil, err
}
clientCAPool := x509.NewCertPool()
clientCAPool.AppendCertsFromPEM(clientCAFile)
config = &tls.Config{
Certificates: []tls.Certificate{cer},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: clientCAPool,
CipherSuites: []uint16{
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
},
PreferServerCipherSuites: true,
SessionTicketsDisabled: false,
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384},
}
return config, nil
}
But what if Julia now want to login ? She will have to create a CSR, send it to me and I would have to manually validate her CSR to a CRT too. To avoid this manual operation, the idea is to have a register endpoint where Julia can submit her CSR and get back a valid CRT. The endpoint will basically look like this :
func Register(c echo.Context) (err error) {
// get Julia's csr from POST body
csr := certificateFromBody(c.Body)
// valid csr with ca to generate the crt
crt := signCSR(csr, config.ClientCAPath)
// return the crt to julia
return c.JSON(http.StatusCreated, base64.StdEncoding.EncodeToString(crt))
}
I spend some time to understand how openssl use the CA to create the CRT from the CRS, without success.
Golang has a CertificateRequest object from the crypto/x509 package that I can create with the ParseCertificateRequest but I can't find the function that take this object and my CA and return a certificate.
Thank you for your help!
You may be able to use x509.CreateCertificate.
One of the parameters to CreateCertificate is a 'template' certificate.
You can set the fields of the template certificate using the fields from Julia's CertificateRequest.
Go's generate cert script shows an example usage CreateCertificate.
This assumes the API request from Julia is really from Julia, and sufficiently trusted to sign the request and return a certificate.
Also, Using your own PKI for TLS in Go may be of help.