Kurt Peek
Kurt Peek

Reputation: 57611

How to verify a certificate against an issuing chain in Go?

I'd like to verify a PEM certificate against an issuing chain which is also a .pem file with several certificates separated by newline characters as shown in this gist, https://gist.github.com/kurtpeek/8bf3282e344c781a20c5deadac75059f. I've tried this with Certpool.AppendCertsFromPEM as follows:

package main

import (
    "crypto/x509"
    "encoding/pem"
    "io/ioutil"

    "github.com/sirupsen/logrus"
)

func main() {
    caCertPEM, err := ioutil.ReadFile("issuing_chain.pem")
    if err != nil {
        logrus.WithError(err).Fatal("read CA PEM file")
    }

    certPEM, err := ioutil.ReadFile("3007e750-e769-440b-9075-41dc2b5b1787.pem")
    if err != nil {
        logrus.WithError(err).Fatal("read cert PEM file")
    }

    block, rest := pem.Decode(certPEM)
    if block == nil {
        logrus.WithField("rest", rest).Fatal("Decode CA PEM")
    }

    cert, err := x509.ParseCertificate(block.Bytes)
    if err != nil {
        logrus.WithError(err).Fatal("parse certificate")
    }

    roots := x509.NewCertPool()
    roots.AppendCertsFromPEM(caCertPEM)

    chain, err := cert.Verify(x509.VerifyOptions{Roots: roots})
    if err != nil {
        logrus.WithError(err).Fatal("failed to verify cert")
    }

    logrus.Infof("issuing chain: %+v", chain)
}

However, if I run this I get the following error:

FATA[0000] failed to verify cert                         error="x509: certificate specifies an incompatible key usage"
exit status 1

I believe this error is returned on line 790 of https://golang.org/src/crypto/x509/verify.go:

if len(chains) == 0 {
    return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
}

In other words, the Verify() method is unable to build any chains from the options provided. I've tried splitting out the intermediates (the top two in the issuing_chain.pem shown in the gist) into a separate PEM file and adding those as Intermediates to the x509.VerifyOptions, but I still get the same error.

What is the correct way to verify a certificate against an issuing chain in Go?

Upvotes: 3

Views: 7953

Answers (1)

Peter
Peter

Reputation: 31720

Your leaf certificate is for client authentication only.

$ openssl x509 -noout -text -in leaf.pem  | grep -A1 'Key Usage'
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: 
                TLS Web Client Authentication

If this is intentional, you must specify the KeyUsages option because "an empty list means ExtKeyUsageServerAuth". You also have to go back to your version of the code that provides the intermediate certs separately:

chain, err := cert.Verify(x509.VerifyOptions{
    Roots:         roots,
    Intermediates: inters,
    KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
})

Try it on the playground: https://play.golang.org/p/1BNLthzu5Tz. Note that the playground requires the CurrentTime option to verify correctly. Remove this when copying elsewhere!

Upvotes: 5

Related Questions