[SOLVED] Help about grpc, I am getting failed to complete security handshake

I’ve already changed many times the port number on the server and client, but the server always get the incorrect port number.

when I execute the client the server will log this:
2017/05/07 15:06:07 grpc: Server.Serve failed to complete security handshake from "127.0.0.1:32763": remote error: tls: bad certificate
and on the client side, i got this:
2017/05/07 15:06:07 Failed to dial localhost:8070: connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"; please retry. rpc error: code = Internal desc = connection error: desc = "transport: x509: certificate is not valid for any names, but wanted to match localhost:8070"

I have this code for the server.go

func serve() {
	addr := "localhost:8070"
	crt, key := certificate.CreatePemKey()
	certificate, err := tls.X509KeyPair(crt, key)
	if err != nil {
		fmt.Println(err)
	}

	certPool := x509.NewCertPool()
	ca, err := ioutil.ReadFile("F:/GIAG3.crt")
	if err != nil {
		fmt.Println(err)
	}

	if ok := certPool.AppendCertsFromPEM(ca); !ok {
		fmt.Println("unable to append certificate")
	}

	lis, err := net.Listen("tcp", addr)
	if err != nil {
		fmt.Println("could not list on %s: %s", addr, err)
	}

	// Create the TLS credentials
	creds := credentials.NewTLS(&tls.Config{
		ClientAuth:   tls.RequireAndVerifyClientCert,
		Certificates: []tls.Certificate{certificate},
		ClientCAs:    certPool,
	})

	srv := grpc.NewServer(grpc.Creds(creds))
	pb.RegisterPingerServer(srv, &server{})

	if err := srv.Serve(lis); err != nil {
		fmt.Println("grpc serve error: %s", err)
	}
}

and this for the client.go

func testDial2() {
	addr := "localhost:8070"
	crt, key := certificate.CreatePemKey()
	certificate, err := tls.X509KeyPair(crt, key)
	if err != nil {
		fmt.Println(err)
	}

	certPool := x509.NewCertPool()
	ca, err := ioutil.ReadFile("F:/GIAG3.crt")
	if err != nil {
		fmt.Println(err)
	}

	if ok := certPool.AppendCertsFromPEM(ca); !ok {
		fmt.Println("unable to append certificate")
	}

	creds := credentials.NewTLS(&tls.Config{
		ServerName:   addr,
		Certificates: []tls.Certificate{certificate},
		RootCAs:      certPool,
	})

	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds))
	if err != nil {
		fmt.Println(err)
	}

	defer conn.Close()
	c := pb.NewPingerClient(conn)
	r, err := c.Ping(context.Background(), &pb.Payload{Message: "Ping"})
	if err != nil {
		fmt.Println(err)
	}
	log.Printf("%s", r.Message)
}

this for the CreatePemKey, it is based on this example https://golang.org/src/crypto/tls/generate_cert.go

func publicKey(priv interface{}) interface{} {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &k.PublicKey
	case *ecdsa.PrivateKey:
		return &k.PublicKey
	default:
		return nil
	}
}

func pemBlockForKey(priv interface{}) *pem.Block {
	switch k := priv.(type) {
	case *rsa.PrivateKey:
		return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
	case *ecdsa.PrivateKey:
		b, err := x509.MarshalECPrivateKey(k)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
			os.Exit(2)
		}
		return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
	default:
		return nil
	}
}

func CreatePemKey() (certpem, keypem []byte) {
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	notBefore := time.Now()
	notAfter := notBefore.AddDate(1, 0, 0)
	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
	serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)

	template := x509.Certificate{
		SerialNumber: serialNumber,
		Subject: pkix.Name{
			Organization: []string{"Acme Co"},
		},
		NotBefore:             notBefore,
		NotAfter:              notAfter,
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
	}
	// template.IPAddresses = append(template.IPAddresses, net.ParseIP("localhost"))
	template.IsCA = true
	derbytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
	certpem = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derbytes})
	keypem = pem.EncodeToMemory(pemBlockForKey(priv))
	return certpem, keypem
}

Please help me, thanks

Edit: the GIAG3.crt is came from here https://pki.goog/

The host name of your server needs to be one of the host names in the certificate.

generate_cert.go does so on line 126

Yes I did that but, I am now getting this transport: x509: certificate signed by unknown authority"; please retry.

The certificate used to sign the server’s certificate needs to be in the client’s RootCA CertPool.

Can i change the topic a little bit? can you suggest any good solution to make the communication of two services securely?
I was just dealing with this TLS connection, because i want to make the handshake of the two services securely. Actually I am still, self teaching about this topic and want to learn more.

Actually I want to learn to make micro services.
Then both services can be on the same machine or it can be on separate machines.

First I have this idea, before a service can communicate to each other, the service that is requesting to other service should do a handshake and exchanging public key on the process.
Then the public key will be used for encrypting messages on both of them.
So that any of them will try to send a message they will encrypt it first.

But I am wondering, what if at the time the handshake is on progress, and there is someone watching the network and spoof the public key and replace it by it own public, then intercept any communication by the services then decryption/encrypting it at the middle. so the system is compromised.

The tutorial you linked to in another post, http://bbengfort.github.io/programmer/2017/03/03/secure-grpc.html, seems to do a reasonable job.

Start by doing what it says.

1 Like

hmm actually the code above is based on that blog. :smile:

“Based on” means you changed something. Since what you are doing is not working, whatever you changed is the reason it is not working.

The way to learn things from tutorials is to first do exactly what they tell you to. This will tell you the tutorial actually works and gives you experience in doing whatever the tutorial teaches.

Then you can start experimenting to get other outcomes.

That’s right, I cant argue you with that.

But I already done the tutorial. Now I am making changes, instead using the openssl to make certificates, I use CreatePemKey and just download CA from google. If I’am right my problem is on the creation of the certificates, and I want to accomplish something that not in the tutorial.

Downloading a CA from google won’t do what you need because to act as a CA you need both the public and private keys. Google only shares the public key. If you had the private key, then you could create certificates as if you were Google. Everyone else could do the same thing.

For making certificates without openssl, the tutorial linked to https://github.com/square/certstrap, which is “written in Go”. Certstrap is also available as a package. I would start by using that to build your CA and certs.

@nathankerr thank you so much, for your time I really appreciate it. BTW how i can mark this thread solve? I cant find the button for it.

You should be able to edit the title.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.