ssh host key certificates, find validity period remotely?

I have an environment where I use ssh certificates to authenticate ssh host keys. I'm talking about the kind of certificates created by running ssh-keygen -s /path/to/ca -h .... These certificates are also created with a validity interval, stating when they will expire. These certificates have now been in use now long enough that I need to start monitor them, to get a heads up when they start getting close to expire.

Any way I can do a remote connection, without logging in, and somehow either get the validity interval displayed alt. get the certificate downloaded? Running ssh -vvv don't appear to display the info I need. Neither does ssh-keyscan appear to be certificate aware. Perhaps some library I haven't looked closely enough at?

Worst case I can always write a monitoring plugin which runs locally and parses the output of ssh-keygen -L -f. Still, a remote scan really feels like the preferable approach.


This is possible, but it lacks tool support. I found a library which speaks the SSH protocol well enough to let me write a tool to extract the host cert valid_before time without a full ssh login. Here it is, in the Go language. I hope it helps.

package main

import "golang.org/x/crypto/ssh"
import "fmt"
import "os"
import "time"

func ignoreCertChain(auth ssh.PublicKey, address string) bool {
    return true // Pretend all certificates are trusted.
}

var sawACert bool

func examineCert(cert *ssh.Certificate) bool {
  expires := cert.ValidBefore
  var humanReadable string
  if expires >= ssh.CertTimeInfinity {
    humanReadable = "infinity"
  } else if expires < (1 << 63) {
    humanReadable = time.Unix(int64(expires), 0).Format(time.RFC3339)
  } else {
    humanReadable = "the distant future"
  }
  fmt.Println("Cert expires at time", expires, "(" + humanReadable + ")")
  sawACert = true
  return true  // Reject the cert, to force early connection close.
}

func main() {
  serverHostPort := os.Args[1]
  checker := &ssh.CertChecker{
    IsHostAuthority: ignoreCertChain,
    IsRevoked: examineCert,
  }
  config := &ssh.ClientConfig{
    User: "test-sshcertscan-not-a-real-login-attempt",
    Auth: []ssh.AuthMethod{
      ssh.Password(""),
    },
    HostKeyCallback: checker.CheckHostKey,
  }
  sawACert = false
  client, err := ssh.Dial("tcp", serverHostPort, config);
  if err != nil && !sawACert {
    panic(fmt.Sprint("Cannot connect to ", serverHostPort, ", error: ",
                     err.Error()))
  } else if client != nil {
    defer client.Close()
  }
}

(Quick usage instructions: install Go, save the code seen above in sshcertscan.go, run go build sshcertscan.go, then point it at an ssh server on examplehost port 22 with ./sshcertscan examplehost:22.)


Unfortunately I don't know of any open-source tool. It seems nmap would be able to retrieve it somehow with NSE scripts (but needs some tweaking -- check /usr/share/nmap/scripts).

SSH's Tectia SSH server includes a tool called ssh-fetchkey that will retrieve the certificate and then you can use ssh-certview to view the details.