1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 type InvalidReason int
15 // NotAuthorizedToSign results when a certificate is signed by another
16 // which isn't marked as a CA certificate.
17 NotAuthorizedToSign InvalidReason = iota
18 // Expired results when a certificate has expired, based on the time
19 // given in the VerifyOptions.
21 // CANotAuthorizedForThisName results when an intermediate or root
22 // certificate has a name constraint which doesn't include the name
24 CANotAuthorizedForThisName
27 // CertificateInvalidError results when an odd error occurs. Users of this
28 // library probably want to handle all these errors uniformly.
29 type CertificateInvalidError struct {
34 func (e CertificateInvalidError) Error() string {
36 case NotAuthorizedToSign:
37 return "x509: certificate is not authorized to sign other other certificates"
39 return "x509: certificate has expired or is not yet valid"
40 case CANotAuthorizedForThisName:
41 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
43 return "x509: unknown error"
46 // HostnameError results when the set of authorized names doesn't match the
48 type HostnameError struct {
49 Certificate *Certificate
53 func (h HostnameError) Error() string {
56 if len(c.DNSNames) > 0 {
57 valid = strings.Join(c.DNSNames, ", ")
59 valid = c.Subject.CommonName
61 return "certificate is valid for " + valid + ", not " + h.Host
64 // UnknownAuthorityError results when the certificate issuer is unknown
65 type UnknownAuthorityError struct {
69 func (e UnknownAuthorityError) Error() string {
70 return "x509: certificate signed by unknown authority"
73 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
74 // because other PKIX verification APIs have ended up needing many options.
75 type VerifyOptions struct {
77 Intermediates *CertPool
79 CurrentTime time.Time // if zero, the current time is used
83 leafCertificate = iota
84 intermediateCertificate
88 // isValid performs validity checks on the c.
89 func (c *Certificate) isValid(certType int, opts *VerifyOptions) error {
90 now := opts.CurrentTime
94 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
95 return CertificateInvalidError{c, Expired}
98 if len(c.PermittedDNSDomains) > 0 {
99 for _, domain := range c.PermittedDNSDomains {
100 if opts.DNSName == domain ||
101 (strings.HasSuffix(opts.DNSName, domain) &&
102 len(opts.DNSName) >= 1+len(domain) &&
103 opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
107 return CertificateInvalidError{c, CANotAuthorizedForThisName}
111 // KeyUsage status flags are ignored. From Engineering Security, Peter
112 // Gutmann: A European government CA marked its signing certificates as
113 // being valid for encryption only, but no-one noticed. Another
114 // European CA marked its signature keys as not being valid for
115 // signatures. A different CA marked its own trusted root certificate
116 // as being invalid for certificate signing. Another national CA
117 // distributed a certificate to be used to encrypt data for the
118 // country’s tax authority that was marked as only being usable for
119 // digital signatures but not for encryption. Yet another CA reversed
120 // the order of the bit flags in the keyUsage due to confusion over
121 // encoding endianness, essentially setting a random keyUsage in
122 // certificates that it issued. Another CA created a self-invalidating
123 // certificate by adding a certificate policy statement stipulating
124 // that the certificate had to be used strictly as specified in the
125 // keyUsage, and a keyUsage containing a flag indicating that the RSA
126 // encryption key could only be used for Diffie-Hellman key agreement.
128 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
129 return CertificateInvalidError{c, NotAuthorizedToSign}
135 // Verify attempts to verify c by building one or more chains from c to a
136 // certificate in opts.roots, using certificates in opts.Intermediates if
137 // needed. If successful, it returns one or chains where the first element of
138 // the chain is c and the last element is from opts.Roots.
140 // WARNING: this doesn't do any revocation checking.
141 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
142 err = c.isValid(leafCertificate, &opts)
146 if len(opts.DNSName) > 0 {
147 err = c.VerifyHostname(opts.DNSName)
152 return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
155 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
156 n := make([]*Certificate, len(chain)+1)
162 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
163 for _, rootNum := range opts.Roots.findVerifiedParents(c) {
164 root := opts.Roots.certs[rootNum]
165 err = root.isValid(rootCertificate, opts)
169 chains = append(chains, appendToFreshChain(currentChain, root))
173 for _, intermediateNum := range opts.Intermediates.findVerifiedParents(c) {
174 intermediate := opts.Intermediates.certs[intermediateNum]
175 for _, cert := range currentChain {
176 if cert == intermediate {
177 continue nextIntermediate
180 err = intermediate.isValid(intermediateCertificate, opts)
184 var childChains [][]*Certificate
185 childChains, ok := cache[intermediateNum]
187 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
188 cache[intermediateNum] = childChains
190 chains = append(chains, childChains...)
197 if len(chains) == 0 && err == nil {
198 err = UnknownAuthorityError{c}
204 func matchHostnames(pattern, host string) bool {
205 if len(pattern) == 0 || len(host) == 0 {
209 patternParts := strings.Split(pattern, ".")
210 hostParts := strings.Split(host, ".")
212 if len(patternParts) != len(hostParts) {
216 for i, patternPart := range patternParts {
217 if patternPart == "*" {
220 if patternPart != hostParts[i] {
228 // VerifyHostname returns nil if c is a valid certificate for the named host.
229 // Otherwise it returns an error describing the mismatch.
230 func (c *Certificate) VerifyHostname(h string) error {
231 if len(c.DNSNames) > 0 {
232 for _, match := range c.DNSNames {
233 if matchHostnames(match, h) {
237 // If Subject Alt Name is given, we ignore the common name.
238 } else if matchHostnames(c.Subject.CommonName, h) {
242 return HostnameError{c, h}