0

I'm trying to read remote website ssl cert with this cli command openssl s_client -connect www.yahoo.no:443 2> /dev/null | openssl x509 -noout -enddate | cut -d = -f 2.

This works fine in cli, but when I execute it in golang:

package main

import (
    "bytes"
    "log"
    "os/exec"
    "time"
)

func main() {
    cmd := exec.Command("echo", "| openssl s_client -connect www.yahoo.com:443 2> /dev/null | openssl x509 -noout -enddate | cut -d = -f 2")
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()

    log.Println(out.String())
}

I get nothing in return. How can I run this command in go?

UPDATE:

this is what I've tried but no success

func command() {

    cmd1 := exec.Command("openssl", "s_client", "-connect", "www.yahoo.no:443", "2>", "/dev/null")
    cmd2 := exec.Command("openssl", "x509", "-noout", "-enddate")

    var out bytes.Buffer

    reader, writer := io.Pipe()
    cmd1.Stdout = writer
    cmd2.Stdin = reader

    cmd2.Stdout = &out

    cmd1.Start()
    cmd2.Start()

    cmd1.Wait()
    writer.Close()

    cmd2.Wait()
    reader.Close()

    io.Copy(&out, reader)
    log.Println(out.String())

}

I get empty response.

6
  • 1
    Pipe | is a shell feature. Instead - use processes stdin and stdout and forward one to another. Commented Dec 17, 2018 at 1:11
  • @zerkms how would I do that (still learning golang)? Commented Dec 17, 2018 at 1:21
  • hint: Create two commands: treat stdout of one process as io.Reader and stdin of another as io.Writer Commented Dec 17, 2018 at 1:23
  • How do I deal with echo? Commented Dec 17, 2018 at 1:30
  • You don't: you have fmt.Printf to print in Go Commented Dec 17, 2018 at 1:42

1 Answer 1

2

Go's standard library contains a perfectly capable TLS implementation, so there is really no reason to launch two hefty openssl processes:

package main

import (
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "time"
)

func main() {
    conn, err := net.Dial("tcp", "example.com:443")
    if err != nil {
            log.Fatal(err)
    }

    client := tls.Client(conn, &tls.Config{
            ServerName: "example.com",
    })
    defer client.Close()

    if err := client.Handshake(); err != nil {
            log.Fatal(err)
    }

    cert := client.ConnectionState().PeerCertificates[0]
    fmt.Println(cert.NotAfter.Format(time.RFC3339)) // Output: 2020-12-02T12:00:00Z
}
Sign up to request clarification or add additional context in comments.

4 Comments

try this url blogspot.es it will exit with status 1. I want to be able to use go routines, if ssl not valid I still need to create some sort of output.
Set the ServerName to one of the valid names ("accounts.blogdiario.com", "www.accounts.blogdiario.com"), or, if you must, enable InsecureSkipVerify.
I actually tried tls before but I've posted question and it was panicing if on this blogspot.es domain. The only part that differs is client.Handshake() I had something else. So now it does not panic but return string that I can check for at the end for not blogspot.es and will know its invalid (as it really is).
How to extract Acceptable client certificate CA Names with this? As peer certificates are only the server certificates?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.