aboutsummaryrefslogtreecommitdiff
path: root/misc/localca/utils.go
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2023-06-19 12:56:31 -0400
committerXe Iaso <me@xeiaso.net>2023-06-19 12:56:31 -0400
commitc592b6d195aedcd6ec86e8c60d3ba91d524e293b (patch)
treefbdb9fe9331ce491d606402d4b62ba5999ce6122 /misc/localca/utils.go
parent84e8f57b98fd1038e6f2fc401277d936ef45522a (diff)
downloadx-c592b6d195aedcd6ec86e8c60d3ba91d524e293b.tar.xz
x-c592b6d195aedcd6ec86e8c60d3ba91d524e293b.zip
second reshuffling
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'misc/localca/utils.go')
-rw-r--r--misc/localca/utils.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/misc/localca/utils.go b/misc/localca/utils.go
new file mode 100644
index 0000000..efc06f3
--- /dev/null
+++ b/misc/localca/utils.go
@@ -0,0 +1,83 @@
+package localca
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "errors"
+ "time"
+)
+
+// validCert parses a cert chain provided as der argument and verifies the leaf and der[0]
+// correspond to the private key, the domain and key type match, and expiration dates
+// are valid. It doesn't do any revocation checking.
+//
+// The returned value is the verified leaf cert.
+func validCert(name string, der [][]byte, key crypto.Signer, now time.Time) (leaf *x509.Certificate, err error) {
+ // parse public part(s)
+ var n int
+ for _, b := range der {
+ n += len(b)
+ }
+ pub := make([]byte, n)
+ n = 0
+ for _, b := range der {
+ n += copy(pub[n:], b)
+ }
+ x509Cert, err := x509.ParseCertificates(pub)
+ if err != nil || len(x509Cert) == 0 {
+ return nil, errors.New("localca: no public key found")
+ }
+ // verify the leaf is not expired and matches the domain name
+ leaf = x509Cert[0]
+ if now.Before(leaf.NotBefore) {
+ return nil, errors.New("localca: certificate is not valid yet")
+ }
+ if now.After(leaf.NotAfter) {
+ return nil, errors.New("localca: expired certificate")
+ }
+ if err := leaf.VerifyHostname(name); err != nil {
+ return nil, err
+ }
+ // ensure the leaf corresponds to the private key and matches the certKey type
+ switch pub := leaf.PublicKey.(type) {
+ case *rsa.PublicKey:
+ prv, ok := key.(*rsa.PrivateKey)
+ if !ok {
+ return nil, errors.New("localca: private key type does not match public key type")
+ }
+ if pub.N.Cmp(prv.N) != 0 {
+ return nil, errors.New("localca: private key does not match public key")
+ }
+ default:
+ return nil, errors.New("localca: unknown public key algorithm")
+ }
+ return leaf, nil
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+//
+// Inspired by parsePrivateKey in crypto/tls/tls.go.
+func parsePrivateKey(der []byte) (crypto.Signer, error) {
+ if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+ return key, nil
+ }
+ if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ return key, nil
+ case *ecdsa.PrivateKey:
+ return key, nil
+ default:
+ return nil, errors.New("localca: unknown private key type in PKCS#8 wrapping")
+ }
+ }
+ if key, err := x509.ParseECPrivateKey(der); err == nil {
+ return key, nil
+ }
+
+ return nil, errors.New("localca: failed to parse private key")
+}