FAQ
dear all,
I'm new with Go.

I would like to implement an HTTPS authentication mechanism using either
X509 certifcate, OAuth...

I have written an HTTPS server just as at the end of this message.

First, to see if this program can validate an user certificate, we can run:
(where /etc/certs/ca contains all known CA certificates)

$> ./bin/main /etc/certs/ca/ mycert.pem mykey.pem
...
INFO : shains = [[0xc208306d80 0xc208189200]]
...

The ouput shows the user certificate is correctly validated


If I remove the CA validating my certificate from /etc/certs/ca, running
the program displays a warning

WARN : failed to parse certificate: x509: certificate signed by unknown
authority


So, I guess user certificate validation works well.


Now, I want my HTTPS server to be able to validate user certificate, but
when I connect (using firefox) I have the following error

2015/05/26 17:23:12 http: TLS handshake error from [::1]:51227: tls: failed
to verify client's certificate: x509: certificate signed by unknown
authority


Any clue?

Thanks,
Oleg Lodygenky





HTTPS server code :

func main() {

         var logger = NewPrefixed("main#main")

         if len(os.Args) < 4 {
                 logger.Fatal("Usage: %v caCertPath certPath keyPath",
os.Args[0])
         }

         //
         // Retrieve CA certificates
         //
         var caRootPool, err = PopulateCertPool(os.Args[1]) // this is
x509.NewCertPool.AppendCertsFromPEM() for all found files
         if err != nil {
                 logger.Fatal(err.Error())
         }

         //
         // Retrieve certificate
         //
         theCert, err := CerficateFromPEMs(os.Args[2], os.Args[3]) // this
is tls.LoadX509KeyPair() and x509.ParseCertificate()
         if err != nil {
                 logger.Fatal(err.Error())
         }

         //
         // Verify cert against known CA
         //
         vOpts := x509.VerifyOptions{Roots: caRootPool}
         chains, err := theCert.Verify(vOpts)
         if err != nil {
                 logger.Warn("failed to parse certificate: " + err.Error())
         }
         logger.Info("shains = %v\n", chains)

         ca_b, _ := ioutil.ReadFile(os.Args[2])
         priv_b, _ := ioutil.ReadFile(os.Args[3])
         priv, _ := x509.ParsePKCS1PrivateKey(priv_b)

         cert := tls.Certificate{
                 Certificate: [][]byte{ca_b},
                 PrivateKey: priv,
         }

         config := tls.Config{
                 RootCAs: caRootPool,
                 Certificates: []tls.Certificate{cert},
                 MinVersion: tls.VersionTLS10,
                 ClientAuth: tls.VerifyClientCertIfGiven,
         }
         config.Rand = rand.Reader
         var a Authenticator

         http.Handle("/", a)
         server := http.Server{Addr: ":4040", TLSConfig: &config}

         // start https
     logger.Info("Listening HTTPS : 4040")

         server.ListenAndServeTLS(os.Args[2], os.Args[3])
}



--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Peter Waller at May 27, 2015 at 7:58 am
    Hi Oleg,

    On 26 May 2015 at 16:24, wrote:>
    config := tls.Config{
    RootCAs: caRootPool,
    Certificates: []tls.Certificate{cert},
    MinVersion: tls.VersionTLS10,
    ClientAuth: tls.VerifyClientCertIfGiven,
    }
    Looking at the go doc, RootCAs seems to only be used for clients
    authenticating servers:

    http://golang.org/pkg/crypto/tls/#Config

    Did you already try to set `ClientCAs:`?

    Hope that helps,

    - Peter

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 8:53 am
    thanks for your answer


    I think I'll first try to use P12 files to see if it works, using
    https://github.com/golang/go/issues/10621

    Because I had to generate my priv/pub keys using the "-nodes" openssl
    option to make it works with my program, otherwise I have the following
    error

    crypto/tls: failed to parse private key



    But my certificate (.P12) stored in Firefox is encrypted



    Oleg


    Le mercredi 27 mai 2015 09:58:27 UTC+2, Peter Waller a écrit :
    Hi Oleg,

    On 26 May 2015 at 16:24, <oleg.lo...@gmail.com <javascript:>> wrote:>
    config := tls.Config{
    RootCAs: caRootPool,
    Certificates: []tls.Certificate{cert},
    MinVersion: tls.VersionTLS10,
    ClientAuth: tls.VerifyClientCertIfGiven,
    }
    Looking at the go doc, RootCAs seems to only be used for clients
    authenticating servers:

    http://golang.org/pkg/crypto/tls/#Config

    Did you already try to set `ClientCAs:`?

    Hope that helps,

    - Peter
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 8:55 am
    thanks for your answer, I'll try that
    :)


    But I relaize I also have to use P12 files, using
    https://github.com/golang/go/issues/10621

    Because I had to generate my priv/pub keys using the "-nodes" openssl
    option to make it works with my program, otherwise I have the following
    error

    crypto/tls: failed to parse private key



    But my certificate (.P12) stored in Firefox is encrypted



    Oleg



    Le mercredi 27 mai 2015 09:58:27 UTC+2, Peter Waller a écrit :
    Hi Oleg,

    On 26 May 2015 at 16:24, <oleg.lo...@gmail.com <javascript:>> wrote:>
    config := tls.Config{
    RootCAs: caRootPool,
    Certificates: []tls.Certificate{cert},
    MinVersion: tls.VersionTLS10,
    ClientAuth: tls.VerifyClientCertIfGiven,
    }
    Looking at the go doc, RootCAs seems to only be used for clients
    authenticating servers:

    http://golang.org/pkg/crypto/tls/#Config

    Did you already try to set `ClientCAs:`?

    Hope that helps,

    - Peter
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 8:59 am
    yes setting ClientCAs seems better
    :)

    But I now have the following error

    tls: client's certificate's extended key usage doesn't permit it to be used
    for client authentication


    Now, I'm digging into that

    :)


    Oleg




    Le mercredi 27 mai 2015 10:55:45 UTC+2, Oleg Lodygensky a écrit :
    thanks for your answer, I'll try that
    :)


    But I relaize I also have to use P12 files, using
    https://github.com/golang/go/issues/10621

    Because I had to generate my priv/pub keys using the "-nodes" openssl
    option to make it works with my program, otherwise I have the following
    error

    crypto/tls: failed to parse private key



    But my certificate (.P12) stored in Firefox is encrypted



    Oleg



    Le mercredi 27 mai 2015 09:58:27 UTC+2, Peter Waller a écrit :
    Hi Oleg,

    On 26 May 2015 at 16:24, wrote:>
    config := tls.Config{
    RootCAs: caRootPool,
    Certificates: []tls.Certificate{cert},
    MinVersion: tls.VersionTLS10,
    ClientAuth: tls.VerifyClientCertIfGiven,
    }
    Looking at the go doc, RootCAs seems to only be used for clients
    authenticating servers:

    http://golang.org/pkg/crypto/tls/#Config

    Did you already try to set `ClientCAs:`?

    Hope that helps,

    - Peter
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 9:20 am
    this is certainly due to my certificate only

    $> openssl x509 -in mycert.pem -inform PEM -text -noout
    [...]
             X509v3 extensions:
                 X509v3 Basic Constraints: critical
                     CA:FALSE
                 Netscape Cert Type:
                     SSL Client, S/MIME, Object Signing
                 X509v3 Key Usage: critical
                     Digital Signature, Non Repudiation, Key Encipherment
    [...]



    Le mercredi 27 mai 2015 10:59:44 UTC+2, Oleg Lodygensky a écrit :
    yes setting ClientCAs seems better
    :)

    But I now have the following error

    tls: client's certificate's extended key usage doesn't permit it to be
    used for client authentication

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 2:06 pm
    Finally everything works
    :)

    First set tls.Config.ClientAuth = tls.RequestClientCert

    Then validate "by hand"


    For those interested, here is the code of the HTTPS server that validates a
    user presenting an X509 cert






    package main

    /*
      * Copyrights : CNRS
      * Author : Oleg Lodygensky
      * Acknowledgment : XtremWeb-HEP is based on XtremWeb 1.8.0 by inria :
    http://www.xtremweb.net/
      * Web : http://www.xtremweb-hep.org
      *
      * This file is part of XtremWeb-HEP.
      *
      * XtremWeb-HEP is free software: you can redistribute it and/or modify
      * it under the terms of the GNU General Public License as published by
      * the Free Software Foundation, either version 3 of the License, or
      * (at your option) any later version.
      *
      * XtremWeb-HEP is distributed in the hope that it will be useful,
      * but WITHOUT ANY WARRANTY; without even the implied warranty of
      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      * GNU General Public License for more details.
      *
      * You should have received a copy of the GNU General Public License
      * along with XtremWeb-HEP. If not, see <http://www.gnu.org/licenses/>.
      *
      */



    import (
         "crypto/rand"
         "crypto/tls"
         "crypto/x509"
         "fmt"
         "io/ioutil"
         "net/http"
         "os"
    )



    /**
      * This is the standard main function
      */
    func main() {

         var logger = NewPrefixed("main#main")

         // verbose := flag.Bool("v", false, "enable/disable verbose mode")

         if len(os.Args) < 4 {
             logger.Fatal("Usage: %v caCertPath serverCertPath serverKeyPath",
    os.Args[0])
         }

         //
         // Retrieve CA certificates
         //
         caRootPool, err := PopulateCertPool(os.Args[1])
         if err != nil {
             logger.Fatal(err.Error())
         }
         logger.Info("CA pool length = %v", len(caRootPool.Subjects()))

         //
         // Retrieve certificate
         //
         serverCert, err := CerficateFromPEMs(os.Args[2], os.Args[3])
         if err != nil {
             logger.Fatal(err.Error())
         }

         logger.Info("serverCert.Subject = %v", serverCert.Subject)
         logger.Info("serverCert.Issuer = %v", serverCert.Issuer)

         //
         // Verify user cert against known CA
         //
         vOpts := x509.VerifyOptions{Roots: caRootPool}
         chains, err := serverCert.Verify(vOpts)
         if err != nil {
             logger.Warn("failed to parse certificate: " + err.Error())
         }
         logger.Info("shains = %v\n", chains)

         ca_b, _ := ioutil.ReadFile(os.Args[2])
         priv_b, _ := ioutil.ReadFile(os.Args[3])
         priv, _ := x509.ParsePKCS1PrivateKey(priv_b)

         cert := tls.Certificate{
             Certificate: [][]byte{ca_b},
             PrivateKey: priv,
         }

         config := tls.Config{
    // RootCAs: caRootPool,
             ClientCAs: caRootPool,
             Certificates: []tls.Certificate{cert},
             //MinVersion: tls.VersionSSL30, //don't use SSLv3,
    https://www.openssl.org/~bodo/ssl-poodle.pdf
             MinVersion: tls.VersionTLS10,
             //MinVersion: tls.VersionTLS11,
             //MinVersion: tls.VersionTLS12,
    // ClientAuth: tls.VerifyClientCertIfGiven,
             ClientAuth: tls.RequestClientCert,
    // ClientAuth: tls.RequireAnyClientCert,
    // ClientAuth: tls.RequireAndVerifyClientCert,
         }
         config.Rand = rand.Reader
         var a Authenticator

         http.Handle("/", a)
         server := http.Server{Addr: ":4040", TLSConfig: &config}

         // start https
         logger.Info("Listening HTTPS : 4040")

         server.ListenAndServeTLS(os.Args[2], os.Args[3])
    }

    type Authenticator struct{}

    func (a Authenticator) ServeHTTP(w http.ResponseWriter,r *http.Request) {

         logger := NewPrefixed("Authenticator#ServHTTP")

         logger.Debug("len(r.TLS.PeerCertificates) = %v",
    len(r.TLS.PeerCertificates))

         if (len(r.TLS.PeerCertificates) < 1) {
             fmt.Fprint(w, "<p>You are not logged in</p>")
             return
         }

         for i, c := range r.TLS.PeerCertificates {
             logger.Debug("r.TLS.PeerCertificates[%v].Subject = %v", i,
    c.Subject)
             logger.Debug("r.TLS.PeerCertificates[%v].Issuer = %v", i, c.Issuer)
             for j, a := range c.EmailAddresses {
                 logger.Debug("r.TLS.PeerCertificates[%v].EmailAddresses[%v] =
    %v", i, j, a)
             }
         }
         logger.Debug("len(r.TLS.VerifiedChains) = %v",
    len(r.TLS.VerifiedChains))

         caRootPool, err := PopulateCertPool(os.Args[1])
         if err != nil {
             fmt.Fprint(w, "<p>Internal error : cant retreive CA Rool Pool</p>")
             return
         }
         logger.Debug("CA pool length = %v", len(caRootPool.Subjects()))

         vOpts := x509.VerifyOptions{Roots: caRootPool}

         userCert := r.TLS.PeerCertificates[0]
         chains, err := userCert.Verify(vOpts)
         if err != nil {
             logger.Warn("failed to parse certificate: " + err.Error())
             fmt.Fprint(w, "<p>Certificate error: can't validate your
    certificate</p>")
             return
         }

         logger.Info("shains = %v\n", chains)

         fmt.Fprint(w, "<p>You are logged in as ", userCert.EmailAddresses[0],
    "</p>")
    }

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Oleg Lodygensky at May 27, 2015 at 8:52 am
    thanks for your answer


    I think I'll first try to use P12 files to see if it works, using
    https://github.com/golang/go/issues/10621

    Because I had to generate my priv/pub keys using the "-nodes" openssl
    option to make it works with my program, otherwise I have the following
    error

    crypto/tls: failed to parse private key



    But my certificate (.P12) stored in Firefox is encrypted



    Oleg



    Le mardi 26 mai 2015 18:39:36 UTC+2, Oleg Lodygensky a écrit :
    dear all,
    I'm new with Go.

    I would like to implement an HTTPS authentication mechanism using either
    X509 certifcate, OAuth...

    I have written an HTTPS server just as at the end of this message.

    First, to see if this program can validate an user certificate, we can run:
    (where /etc/certs/ca contains all known CA certificates)

    $> ./bin/main /etc/certs/ca/ mycert.pem mykey.pem
    ...
    INFO : shains = [[0xc208306d80 0xc208189200]]
    ...

    The ouput shows the user certificate is correctly validated


    If I remove the CA validating my certificate from /etc/certs/ca, running
    the program displays a warning

    WARN : failed to parse certificate: x509: certificate signed by unknown
    authority


    So, I guess user certificate validation works well.


    Now, I want my HTTPS server to be able to validate user certificate, but
    when I connect (using firefox) I have the following error

    2015/05/26 17:23:12 http: TLS handshake error from [::1]:51227: tls:
    failed to verify client's certificate: x509: certificate signed by unknown
    authority


    Any clue?

    Thanks,
    Oleg Lodygenky





    HTTPS server code :

    func main() {

    var logger = NewPrefixed("main#main")

    if len(os.Args) < 4 {
    logger.Fatal("Usage: %v caCertPath certPath keyPath",
    os.Args[0])
    }

    //
    // Retrieve CA certificates
    //
    var caRootPool, err = PopulateCertPool(os.Args[1]) // this is
    x509.NewCertPool.AppendCertsFromPEM() for all found files
    if err != nil {
    logger.Fatal(err.Error())
    }

    //
    // Retrieve certificate
    //
    theCert, err := CerficateFromPEMs(os.Args[2], os.Args[3]) //
    this is tls.LoadX509KeyPair() and x509.ParseCertificate()
    if err != nil {
    logger.Fatal(err.Error())
    }

    //
    // Verify cert against known CA
    //
    vOpts := x509.VerifyOptions{Roots: caRootPool}
    chains, err := theCert.Verify(vOpts)
    if err != nil {
    logger.Warn("failed to parse certificate: " + err.Error())
    }
    logger.Info("shains = %v\n", chains)

    ca_b, _ := ioutil.ReadFile(os.Args[2])
    priv_b, _ := ioutil.ReadFile(os.Args[3])
    priv, _ := x509.ParsePKCS1PrivateKey(priv_b)

    cert := tls.Certificate{
    Certificate: [][]byte{ca_b},
    PrivateKey: priv,
    }

    config := tls.Config{
    RootCAs: caRootPool,
    Certificates: []tls.Certificate{cert},
    MinVersion: tls.VersionTLS10,
    ClientAuth: tls.VerifyClientCertIfGiven,
    }
    config.Rand = rand.Reader
    var a Authenticator

    http.Handle("/", a)
    server := http.Server{Addr: ":4040", TLSConfig: &config}

    // start https
    logger.Info("Listening HTTPS : 4040")

    server.ListenAndServeTLS(os.Args[2], os.Args[3])
    }


    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedMay 26, '15 at 4:39p
activeMay 27, '15 at 2:06p
posts8
users2
websitegolang.org

2 users in discussion

Oleg Lodygensky: 7 posts Peter Waller: 1 post

People

Translate

site design / logo © 2022 Grokbase