package acmeserver import ( "crypto" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "errors" "fmt" "time" ) // Verify that a certificate is valid according both to the current // time and to the specified parameters. func validCert(domains []string, der [][]byte, key crypto.Signer) (*x509.Certificate, error) { leaf, err := leafCertFromDER(der) if err != nil { return nil, err } // Verify the leaf is not expired. if err := isCertExpired(leaf); err != nil { return nil, err } // Verify that it matches the given domains. if err := certMatchesDomains(leaf, domains); err != nil { return nil, err } // Verify that it matches the private key. if err := certMatchesPrivateKey(leaf, key); err != nil { return nil, err } return leaf, nil } func leafCertFromDER(der [][]byte) (*x509.Certificate, error) { x509Cert, err := x509.ParseCertificates(concatDER(der)) if err != nil { return nil, err } if len(x509Cert) == 0 { return nil, errors.New("no public key found") } return x509Cert[0], nil } func isCertExpired(cert *x509.Certificate) error { now := time.Now() if now.Before(cert.NotBefore) { return errors.New("certificate isn't valid yet") } if now.After(cert.NotAfter) { return errors.New("certificate expired") } return nil } func certMatchesDomains(cert *x509.Certificate, domains []string) error { for _, domain := range domains { if err := cert.VerifyHostname(domain); err != nil { return fmt.Errorf("certificate does not match domain %q", domain) } } return nil } func certMatchesPrivateKey(cert *x509.Certificate, key crypto.Signer) error { switch pub := cert.PublicKey.(type) { case *rsa.PublicKey: prv, ok := key.(*rsa.PrivateKey) if !ok { return errors.New("private key type does not match public key type") } if pub.N.Cmp(prv.N) != 0 { return errors.New("private key does not match public key") } case *ecdsa.PublicKey: prv, ok := key.(*ecdsa.PrivateKey) if !ok { return errors.New("private key type does not match public key type") } if pub.X.Cmp(prv.X) != 0 || pub.Y.Cmp(prv.Y) != 0 { return errors.New("private key does not match public key") } default: return errors.New("unsupported public key algorithm") } return nil }