14 type InvalidReason int
17 // NotAuthorizedToSign results when a certificate is signed by another
18 // which isn't marked as a CA certificate.
19 NotAuthorizedToSign InvalidReason = iota
20 // Expired results when a certificate has expired, based on the time
21 // given in the VerifyOptions.
23 // CANotAuthorizedForThisName results when an intermediate or root
24 // certificate has a name constraint which doesn't include the name
26 CANotAuthorizedForThisName
27 // TooManyIntermediates results when a path length constraint is
30 // IncompatibleUsage results when the certificate's key usage indicates
31 // that it may only be used for a different purpose.
33 // NameMismatch results when the subject name of a parent certificate
34 // does not match the issuer name in the child.
38 // CertificateInvalidError results when an odd error occurs. Users of this
39 // library probably want to handle all these errors uniformly.
40 type CertificateInvalidError struct {
45 func (e CertificateInvalidError) Error() string {
47 case NotAuthorizedToSign:
48 return "x509: certificate is not authorized to sign other certificates"
50 return "x509: certificate has expired or is not yet valid"
51 case CANotAuthorizedForThisName:
52 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
53 case TooManyIntermediates:
54 return "x509: too many intermediates for path length constraint"
55 case IncompatibleUsage:
56 return "x509: certificate specifies an incompatible key usage"
58 return "x509: issuer name does not match subject from issuing certificate"
60 return "x509: unknown error"
63 // HostnameError results when the set of authorized names doesn't match the
65 type HostnameError struct {
66 Certificate *Certificate
70 func (h HostnameError) Error() string {
74 if ip := net.ParseIP(h.Host); ip != nil {
75 // Trying to validate an IP
76 if len(c.IPAddresses) == 0 {
77 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
79 for _, san := range c.IPAddresses {
86 if len(c.DNSNames) > 0 {
87 valid = strings.Join(c.DNSNames, ", ")
89 valid = c.Subject.CommonName
94 return "x509: certificate is not valid for any names, but wanted to match " + h.Host
96 return "x509: certificate is valid for " + valid + ", not " + h.Host
99 // UnknownAuthorityError results when the certificate issuer is unknown
100 type UnknownAuthorityError struct {
102 // hintErr contains an error that may be helpful in determining why an
103 // authority wasn't found.
105 // hintCert contains a possible authority certificate that was rejected
106 // because of the error in hintErr.
107 hintCert *Certificate
110 func (e UnknownAuthorityError) Error() string {
111 s := "x509: certificate signed by unknown authority"
112 if e.hintErr != nil {
113 certName := e.hintCert.Subject.CommonName
114 if len(certName) == 0 {
115 if len(e.hintCert.Subject.Organization) > 0 {
116 certName = e.hintCert.Subject.Organization[0]
118 certName = "serial:" + e.hintCert.SerialNumber.String()
121 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
126 // SystemRootsError results when we fail to load the system root certificates.
127 type SystemRootsError struct {
131 func (se SystemRootsError) Error() string {
132 msg := "x509: failed to load system roots and no roots provided"
134 return msg + "; " + se.Err.Error()
139 // errNotParsed is returned when a certificate without ASN.1 contents is
140 // verified. Platform-specific verification needs the ASN.1 contents.
141 var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
143 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
144 // because other PKIX verification APIs have ended up needing many options.
145 type VerifyOptions struct {
147 Intermediates *CertPool
148 Roots *CertPool // if nil, the system roots are used
149 CurrentTime time.Time // if zero, the current time is used
150 // KeyUsage specifies which Extended Key Usage values are acceptable.
151 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
152 // constraint down the chain which mirrors Windows CryptoAPI behavior,
153 // but not the spec. To accept any key usage, include ExtKeyUsageAny.
154 KeyUsages []ExtKeyUsage
158 leafCertificate = iota
159 intermediateCertificate
163 func matchNameConstraint(domain, constraint string) bool {
164 // The meaning of zero length constraints is not specified, but this
165 // code follows NSS and accepts them as valid for everything.
166 if len(constraint) == 0 {
170 if len(domain) < len(constraint) {
174 prefixLen := len(domain) - len(constraint)
175 if !strings.EqualFold(domain[prefixLen:], constraint) {
183 isSubdomain := domain[prefixLen-1] == '.'
184 constraintHasLeadingDot := constraint[0] == '.'
185 return isSubdomain != constraintHasLeadingDot
188 // isValid performs validity checks on the c.
189 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
190 if len(currentChain) > 0 {
191 child := currentChain[len(currentChain)-1]
192 if !bytes.Equal(child.RawIssuer, c.RawSubject) {
193 return CertificateInvalidError{c, NameMismatch}
196 now := opts.CurrentTime
200 if now.Before(c.NotBefore) || now.After(c.NotAfter) {
201 return CertificateInvalidError{c, Expired}
203 if len(c.PermittedDNSDomains) > 0 {
205 for _, constraint := range c.PermittedDNSDomains {
206 ok = matchNameConstraint(opts.DNSName, constraint)
213 return CertificateInvalidError{c, CANotAuthorizedForThisName}
217 // KeyUsage status flags are ignored. From Engineering Security, Peter
218 // Gutmann: A European government CA marked its signing certificates as
219 // being valid for encryption only, but no-one noticed. Another
220 // European CA marked its signature keys as not being valid for
221 // signatures. A different CA marked its own trusted root certificate
222 // as being invalid for certificate signing. Another national CA
223 // distributed a certificate to be used to encrypt data for the
224 // country’s tax authority that was marked as only being usable for
225 // digital signatures but not for encryption. Yet another CA reversed
226 // the order of the bit flags in the keyUsage due to confusion over
227 // encoding endianness, essentially setting a random keyUsage in
228 // certificates that it issued. Another CA created a self-invalidating
229 // certificate by adding a certificate policy statement stipulating
230 // that the certificate had to be used strictly as specified in the
231 // keyUsage, and a keyUsage containing a flag indicating that the RSA
232 // encryption key could only be used for Diffie-Hellman key agreement.
234 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
235 return CertificateInvalidError{c, NotAuthorizedToSign}
238 if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
239 numIntermediates := len(currentChain) - 1
240 if numIntermediates > c.MaxPathLen {
241 return CertificateInvalidError{c, TooManyIntermediates}
248 // Verify attempts to verify c by building one or more chains from c to a
249 // certificate in opts.Roots, using certificates in opts.Intermediates if
250 // needed. If successful, it returns one or more chains where the first
251 // element of the chain is c and the last element is from opts.Roots.
253 // If opts.Roots is nil and system roots are unavailable the returned error
254 // will be of type SystemRootsError.
256 // WARNING: this doesn't do any revocation checking.
257 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
258 // Platform-specific verification needs the ASN.1 contents so
259 // this makes the behavior consistent across platforms.
261 return nil, errNotParsed
263 if opts.Intermediates != nil {
264 for _, intermediate := range opts.Intermediates.certs {
265 if len(intermediate.Raw) == 0 {
266 return nil, errNotParsed
271 // Use Windows's own verification and chain building.
272 if opts.Roots == nil && runtime.GOOS == "windows" {
273 return c.systemVerify(&opts)
276 if len(c.UnhandledCriticalExtensions) > 0 {
277 return nil, UnhandledCriticalExtension{}
280 if opts.Roots == nil {
281 opts.Roots = systemRootsPool()
282 if opts.Roots == nil {
283 return nil, SystemRootsError{systemRootsErr}
287 err = c.isValid(leafCertificate, nil, &opts)
292 if len(opts.DNSName) > 0 {
293 err = c.VerifyHostname(opts.DNSName)
299 var candidateChains [][]*Certificate
300 if opts.Roots.contains(c) {
301 candidateChains = append(candidateChains, []*Certificate{c})
303 if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
308 keyUsages := opts.KeyUsages
309 if len(keyUsages) == 0 {
310 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
313 // If any key usage is acceptable then we're done.
314 for _, usage := range keyUsages {
315 if usage == ExtKeyUsageAny {
316 chains = candidateChains
321 for _, candidate := range candidateChains {
322 if checkChainForKeyUsage(candidate, keyUsages) {
323 chains = append(chains, candidate)
327 if len(chains) == 0 {
328 err = CertificateInvalidError{c, IncompatibleUsage}
334 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
335 n := make([]*Certificate, len(chain)+1)
341 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
342 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
344 for _, rootNum := range possibleRoots {
345 root := opts.Roots.certs[rootNum]
347 for _, cert := range currentChain {
348 if cert.Equal(root) {
353 err = root.isValid(rootCertificate, currentChain, opts)
357 chains = append(chains, appendToFreshChain(currentChain, root))
360 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c)
362 for _, intermediateNum := range possibleIntermediates {
363 intermediate := opts.Intermediates.certs[intermediateNum]
364 for _, cert := range currentChain {
365 if cert.Equal(intermediate) {
366 continue nextIntermediate
369 err = intermediate.isValid(intermediateCertificate, currentChain, opts)
373 var childChains [][]*Certificate
374 childChains, ok := cache[intermediateNum]
376 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts)
377 cache[intermediateNum] = childChains
379 chains = append(chains, childChains...)
386 if len(chains) == 0 && err == nil {
388 hintCert := failedRoot
390 hintErr = intermediateErr
391 hintCert = failedIntermediate
393 err = UnknownAuthorityError{c, hintErr, hintCert}
399 func matchHostnames(pattern, host string) bool {
400 host = strings.TrimSuffix(host, ".")
401 pattern = strings.TrimSuffix(pattern, ".")
403 if len(pattern) == 0 || len(host) == 0 {
407 patternParts := strings.Split(pattern, ".")
408 hostParts := strings.Split(host, ".")
410 if len(patternParts) != len(hostParts) {
414 for i, patternPart := range patternParts {
415 if i == 0 && patternPart == "*" {
418 if patternPart != hostParts[i] {
426 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
427 // an explicitly ASCII function to avoid any sharp corners resulting from
428 // performing Unicode operations on DNS labels.
429 func toLowerCaseASCII(in string) string {
430 // If the string is already lower-case then there's nothing to do.
431 isAlreadyLowerCase := true
432 for _, c := range in {
433 if c == utf8.RuneError {
434 // If we get a UTF-8 error then there might be
435 // upper-case ASCII bytes in the invalid sequence.
436 isAlreadyLowerCase = false
439 if 'A' <= c && c <= 'Z' {
440 isAlreadyLowerCase = false
445 if isAlreadyLowerCase {
450 for i, c := range out {
451 if 'A' <= c && c <= 'Z' {
458 // VerifyHostname returns nil if c is a valid certificate for the named host.
459 // Otherwise it returns an error describing the mismatch.
460 func (c *Certificate) VerifyHostname(h string) error {
461 // IP addresses may be written in [ ].
463 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
464 candidateIP = h[1 : len(h)-1]
466 if ip := net.ParseIP(candidateIP); ip != nil {
467 // We only match IP addresses against IP SANs.
468 // https://tools.ietf.org/html/rfc6125#appendix-B.2
469 for _, candidate := range c.IPAddresses {
470 if ip.Equal(candidate) {
474 return HostnameError{c, candidateIP}
477 lowered := toLowerCaseASCII(h)
479 if len(c.DNSNames) > 0 {
480 for _, match := range c.DNSNames {
481 if matchHostnames(toLowerCaseASCII(match), lowered) {
485 // If Subject Alt Name is given, we ignore the common name.
486 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
490 return HostnameError{c, h}
493 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
494 usages := make([]ExtKeyUsage, len(keyUsages))
495 copy(usages, keyUsages)
501 usagesRemaining := len(usages)
503 // We walk down the list and cross out any usages that aren't supported
504 // by each certificate. If we cross out all the usages, then the chain
508 for i := len(chain) - 1; i >= 0; i-- {
510 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
511 // The certificate doesn't have any extended key usage specified.
515 for _, usage := range cert.ExtKeyUsage {
516 if usage == ExtKeyUsageAny {
517 // The certificate is explicitly good for any usage.
522 const invalidUsage ExtKeyUsage = -1
525 for i, requestedUsage := range usages {
526 if requestedUsage == invalidUsage {
530 for _, usage := range cert.ExtKeyUsage {
531 if requestedUsage == usage {
532 continue NextRequestedUsage
533 } else if requestedUsage == ExtKeyUsageServerAuth &&
534 (usage == ExtKeyUsageNetscapeServerGatedCrypto ||
535 usage == ExtKeyUsageMicrosoftServerGatedCrypto) {
536 // In order to support COMODO
537 // certificate chains, we have to
538 // accept Netscape or Microsoft SGC
539 // usages as equal to ServerAuth.
540 continue NextRequestedUsage
544 usages[i] = invalidUsage
546 if usagesRemaining == 0 {