aboutsummaryrefslogtreecommitdiff
path: root/pkg/crtutil/crt_util.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/crtutil/crt_util.go')
-rw-r--r--pkg/crtutil/crt_util.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/pkg/crtutil/crt_util.go b/pkg/crtutil/crt_util.go
new file mode 100644
index 0000000..11bcd7e
--- /dev/null
+++ b/pkg/crtutil/crt_util.go
@@ -0,0 +1,71 @@
+// Package crtutil provides utility functions for working with certificates.
+package crtutil
+
+import (
+ "crypto/sha256"
+ "encoding/pem"
+ "fmt"
+
+ ct "github.com/google/certificate-transparency-go"
+ "github.com/google/certificate-transparency-go/x509"
+)
+
+// CertificateChainFromPEM parses a certificate chain in PEM format. At least
+// one certificate must be in the chain. The first certificate must be a leaf,
+// whereas all other certificates must CA certificates (intermdiates/roots).
+func CertificateChainFromPEM(b []byte) ([]x509.Certificate, error) {
+ var chain []x509.Certificate
+
+ for {
+ block, rest := pem.Decode(b)
+ if block == nil {
+ break
+ }
+ crt, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ return nil, fmt.Errorf("parse certificate: %v", err)
+ }
+
+ chain = append(chain, *crt)
+ b = rest
+ }
+
+ if len(chain) == 0 {
+ return nil, fmt.Errorf("no certificates in the provided chain")
+ }
+ if chain[0].IsCA {
+ return nil, fmt.Errorf("leaf certificate has the CA bit set")
+ }
+ for _, crt := range chain[1:] {
+ if !crt.IsCA {
+ return nil, fmt.Errorf("non-leaf certificate without the CA bit set")
+ }
+ }
+
+ return chain, nil
+}
+
+// CertificateFromLogEntry parses the (pre-)certificate in a log entry
+func CertificateFromLogEntry(leafData, extraData []byte) (x509.Certificate, error) {
+ entry, err := ct.LogEntryFromLeaf(0, &ct.LeafEntry{LeafInput: leafData, ExtraData: extraData})
+ if err != nil {
+ return x509.Certificate{}, fmt.Errorf("parse leaf: %v", err)
+ }
+ if entry.Precert == nil && entry.X509Cert == nil {
+ return x509.Certificate{}, fmt.Errorf("neither precertificate nor certificate in leaf")
+ }
+ if entry.Precert != nil && entry.X509Cert != nil {
+ return x509.Certificate{}, fmt.Errorf("both certificate and precertificate in leaf")
+ }
+ if entry.Precert != nil {
+ return *entry.Precert.TBSCertificate, nil
+ }
+ return *entry.X509Cert, nil
+}
+
+// UniqueID derives a unique certificate ID. The same value is derived
+// regardless of if the (pre-)certificate is logged multiple times.
+func UniqueID(crt x509.Certificate) string {
+ h := sha256.Sum256([]byte(crt.SerialNumber.String()))
+ return fmt.Sprintf("FIXME:%x", h[:]) // not a secure mapping
+}