diff options
| author | Xe Iaso <me@xeiaso.net> | 2023-06-19 12:56:31 -0400 |
|---|---|---|
| committer | Xe Iaso <me@xeiaso.net> | 2023-06-19 12:56:31 -0400 |
| commit | c592b6d195aedcd6ec86e8c60d3ba91d524e293b (patch) | |
| tree | fbdb9fe9331ce491d606402d4b62ba5999ce6122 /misc/localca/utils.go | |
| parent | 84e8f57b98fd1038e6f2fc401277d936ef45522a (diff) | |
| download | x-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.go | 83 |
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") +} |
