aboutsummaryrefslogtreecommitdiff
path: root/internal/x509util
diff options
context:
space:
mode:
Diffstat (limited to 'internal/x509util')
-rw-r--r--internal/x509util/x509util.go44
1 files changed, 44 insertions, 0 deletions
diff --git a/internal/x509util/x509util.go b/internal/x509util/x509util.go
new file mode 100644
index 0000000..912d1b4
--- /dev/null
+++ b/internal/x509util/x509util.go
@@ -0,0 +1,44 @@
+package x509util
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+)
+
+// ParseChain 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).
+//
+// Note: it is not checked if the certificate chain's root is trusted or not.
+func ParseChain(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
+}