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") }