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.

  • Comparing the output of ssh -vvv with a certified host key to what it looks like with an ordinary host key could provide some clue as to where to start looking for an answer. – kasperd Aug 12 '14 at 21:42
  • It does not, only the fingerprint gets printed. – Dennis Kaarsemaker Aug 15 '14 at 13:19
  • openssl s_client -showcerts would work for a web server. I don't have an ssh server with a cert based key to test it on. – Fred the Magic Wonder Dog Aug 15 '14 at 21:12

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{
    HostKeyCallback: checker.CheckHostKey,
  sawACert = false
  client, err := ssh.Dial("tcp", serverHostPort, config);
  if err != nil && !sawACert {
    panic(fmt.Sprint("Cannot connect to ", serverHostPort, ", 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.)

  • Wow, also writing that example code certainly went way over and beyond, thanks! Now I just need to learn a bit more go :) – andol Aug 17 '14 at 17:52

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.

  • While I might not use NSE scripts for this purpose, it definitely sounds like something I might find future uses for. Thanks! – andol Aug 17 '14 at 17:53

I'm afraid the answer is "that's not possible". At least not in any way I found, using either the openssh client or the paramiko SSH library for python. I would suggest a local check as you described, combined with a simpler remote check that verifies that the key used by SSHD is the key you just checked the certificate lifetime of.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.