github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/src/crypto/x509/verify.go (about) 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. 4 5 package x509 6 7 import ( 8 "fmt" 9 "net" 10 "runtime" 11 "strings" 12 "time" 13 "unicode/utf8" 14 ) 15 16 type InvalidReason int 17 18 const ( 19 // NotAuthorizedToSign results when a certificate is signed by another 20 // which isn't marked as a CA certificate. 21 NotAuthorizedToSign InvalidReason = iota 22 // Expired results when a certificate has expired, based on the time 23 // given in the VerifyOptions. 24 Expired 25 // CANotAuthorizedForThisName results when an intermediate or root 26 // certificate has a name constraint which doesn't include the name 27 // being checked. 28 CANotAuthorizedForThisName 29 // TooManyIntermediates results when a path length constraint is 30 // violated. 31 TooManyIntermediates 32 // IncompatibleUsage results when the certificate's key usage indicates 33 // that it may only be used for a different purpose. 34 IncompatibleUsage 35 ) 36 37 // CertificateInvalidError results when an odd error occurs. Users of this 38 // library probably want to handle all these errors uniformly. 39 type CertificateInvalidError struct { 40 Cert *Certificate 41 Reason InvalidReason 42 } 43 44 func (e CertificateInvalidError) Error() string { 45 switch e.Reason { 46 case NotAuthorizedToSign: 47 return "x509: certificate is not authorized to sign other certificates" 48 case Expired: 49 return "x509: certificate has expired or is not yet valid" 50 case CANotAuthorizedForThisName: 51 return "x509: a root or intermediate certificate is not authorized to sign in this domain" 52 case TooManyIntermediates: 53 return "x509: too many intermediates for path length constraint" 54 case IncompatibleUsage: 55 return "x509: certificate specifies an incompatible key usage" 56 } 57 return "x509: unknown error" 58 } 59 60 // HostnameError results when the set of authorized names doesn't match the 61 // requested name. 62 type HostnameError struct { 63 Certificate *Certificate 64 Host string 65 } 66 67 func (h HostnameError) Error() string { 68 c := h.Certificate 69 70 var valid string 71 if ip := net.ParseIP(h.Host); ip != nil { 72 // Trying to validate an IP 73 if len(c.IPAddresses) == 0 { 74 return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" 75 } 76 for _, san := range c.IPAddresses { 77 if len(valid) > 0 { 78 valid += ", " 79 } 80 valid += san.String() 81 } 82 } else { 83 if len(c.DNSNames) > 0 { 84 valid = strings.Join(c.DNSNames, ", ") 85 } else { 86 valid = c.Subject.CommonName 87 } 88 } 89 return "x509: certificate is valid for " + valid + ", not " + h.Host 90 } 91 92 // UnknownAuthorityError results when the certificate issuer is unknown 93 type UnknownAuthorityError struct { 94 cert *Certificate 95 // hintErr contains an error that may be helpful in determining why an 96 // authority wasn't found. 97 hintErr error 98 // hintCert contains a possible authority certificate that was rejected 99 // because of the error in hintErr. 100 hintCert *Certificate 101 } 102 103 func (e UnknownAuthorityError) Error() string { 104 s := "x509: certificate signed by unknown authority" 105 if e.hintErr != nil { 106 certName := e.hintCert.Subject.CommonName 107 if len(certName) == 0 { 108 if len(e.hintCert.Subject.Organization) > 0 { 109 certName = e.hintCert.Subject.Organization[0] 110 } 111 certName = "serial:" + e.hintCert.SerialNumber.String() 112 } 113 s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName) 114 } 115 return s 116 } 117 118 // SystemRootsError results when we fail to load the system root certificates. 119 type SystemRootsError struct{} 120 121 func (SystemRootsError) Error() string { 122 return "x509: failed to load system roots and no roots provided" 123 } 124 125 // VerifyOptions contains parameters for Certificate.Verify. It's a structure 126 // because other PKIX verification APIs have ended up needing many options. 127 type VerifyOptions struct { 128 DNSName string 129 Intermediates *CertPool 130 Roots *CertPool // if nil, the system roots are used 131 CurrentTime time.Time // if zero, the current time is used 132 // KeyUsage specifies which Extended Key Usage values are acceptable. 133 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a 134 // constraint down the chain which mirrors Windows CryptoAPI behaviour, 135 // but not the spec. To accept any key usage, include ExtKeyUsageAny. 136 KeyUsages []ExtKeyUsage 137 } 138 139 const ( 140 leafCertificate = iota 141 intermediateCertificate 142 rootCertificate 143 ) 144 145 // isValid performs validity checks on the c. 146 func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error { 147 now := opts.CurrentTime 148 if now.IsZero() { 149 now = time.Now() 150 } 151 if now.Before(c.NotBefore) || now.After(c.NotAfter) { 152 return CertificateInvalidError{c, Expired} 153 } 154 155 if len(c.PermittedDNSDomains) > 0 { 156 ok := false 157 for _, domain := range c.PermittedDNSDomains { 158 if opts.DNSName == domain || 159 (strings.HasSuffix(opts.DNSName, domain) && 160 len(opts.DNSName) >= 1+len(domain) && 161 opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') { 162 ok = true 163 break 164 } 165 } 166 167 if !ok { 168 return CertificateInvalidError{c, CANotAuthorizedForThisName} 169 } 170 } 171 172 // KeyUsage status flags are ignored. From Engineering Security, Peter 173 // Gutmann: A European government CA marked its signing certificates as 174 // being valid for encryption only, but no-one noticed. Another 175 // European CA marked its signature keys as not being valid for 176 // signatures. A different CA marked its own trusted root certificate 177 // as being invalid for certificate signing. Another national CA 178 // distributed a certificate to be used to encrypt data for the 179 // country’s tax authority that was marked as only being usable for 180 // digital signatures but not for encryption. Yet another CA reversed 181 // the order of the bit flags in the keyUsage due to confusion over 182 // encoding endianness, essentially setting a random keyUsage in 183 // certificates that it issued. Another CA created a self-invalidating 184 // certificate by adding a certificate policy statement stipulating 185 // that the certificate had to be used strictly as specified in the 186 // keyUsage, and a keyUsage containing a flag indicating that the RSA 187 // encryption key could only be used for Diffie-Hellman key agreement. 188 189 if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) { 190 return CertificateInvalidError{c, NotAuthorizedToSign} 191 } 192 193 if c.BasicConstraintsValid && c.MaxPathLen >= 0 { 194 numIntermediates := len(currentChain) - 1 195 if numIntermediates > c.MaxPathLen { 196 return CertificateInvalidError{c, TooManyIntermediates} 197 } 198 } 199 200 return nil 201 } 202 203 // Verify attempts to verify c by building one or more chains from c to a 204 // certificate in opts.Roots, using certificates in opts.Intermediates if 205 // needed. If successful, it returns one or more chains where the first 206 // element of the chain is c and the last element is from opts.Roots. 207 // 208 // If opts.Roots is nil and system roots are unavailable the returned error 209 // will be of type SystemRootsError. 210 // 211 // WARNING: this doesn't do any revocation checking. 212 func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) { 213 // Use Windows's own verification and chain building. 214 if opts.Roots == nil && runtime.GOOS == "windows" { 215 return c.systemVerify(&opts) 216 } 217 218 if len(c.UnhandledCriticalExtensions) > 0 { 219 return nil, UnhandledCriticalExtension{} 220 } 221 222 if opts.Roots == nil { 223 opts.Roots = systemRootsPool() 224 if opts.Roots == nil { 225 return nil, SystemRootsError{} 226 } 227 } 228 229 err = c.isValid(leafCertificate, nil, &opts) 230 if err != nil { 231 return 232 } 233 234 if len(opts.DNSName) > 0 { 235 err = c.VerifyHostname(opts.DNSName) 236 if err != nil { 237 return 238 } 239 } 240 241 candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) 242 if err != nil { 243 return 244 } 245 246 keyUsages := opts.KeyUsages 247 if len(keyUsages) == 0 { 248 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} 249 } 250 251 // If any key usage is acceptable then we're done. 252 for _, usage := range keyUsages { 253 if usage == ExtKeyUsageAny { 254 chains = candidateChains 255 return 256 } 257 } 258 259 for _, candidate := range candidateChains { 260 if checkChainForKeyUsage(candidate, keyUsages) { 261 chains = append(chains, candidate) 262 } 263 } 264 265 if len(chains) == 0 { 266 err = CertificateInvalidError{c, IncompatibleUsage} 267 } 268 269 return 270 } 271 272 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { 273 n := make([]*Certificate, len(chain)+1) 274 copy(n, chain) 275 n[len(chain)] = cert 276 return n 277 } 278 279 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) { 280 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c) 281 for _, rootNum := range possibleRoots { 282 root := opts.Roots.certs[rootNum] 283 err = root.isValid(rootCertificate, currentChain, opts) 284 if err != nil { 285 continue 286 } 287 chains = append(chains, appendToFreshChain(currentChain, root)) 288 } 289 290 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c) 291 nextIntermediate: 292 for _, intermediateNum := range possibleIntermediates { 293 intermediate := opts.Intermediates.certs[intermediateNum] 294 for _, cert := range currentChain { 295 if cert == intermediate { 296 continue nextIntermediate 297 } 298 } 299 err = intermediate.isValid(intermediateCertificate, currentChain, opts) 300 if err != nil { 301 continue 302 } 303 var childChains [][]*Certificate 304 childChains, ok := cache[intermediateNum] 305 if !ok { 306 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts) 307 cache[intermediateNum] = childChains 308 } 309 chains = append(chains, childChains...) 310 } 311 312 if len(chains) > 0 { 313 err = nil 314 } 315 316 if len(chains) == 0 && err == nil { 317 hintErr := rootErr 318 hintCert := failedRoot 319 if hintErr == nil { 320 hintErr = intermediateErr 321 hintCert = failedIntermediate 322 } 323 err = UnknownAuthorityError{c, hintErr, hintCert} 324 } 325 326 return 327 } 328 329 func matchHostnames(pattern, host string) bool { 330 host = strings.TrimSuffix(host, ".") 331 pattern = strings.TrimSuffix(pattern, ".") 332 333 if len(pattern) == 0 || len(host) == 0 { 334 return false 335 } 336 337 patternParts := strings.Split(pattern, ".") 338 hostParts := strings.Split(host, ".") 339 340 if len(patternParts) != len(hostParts) { 341 return false 342 } 343 344 for i, patternPart := range patternParts { 345 if i == 0 && patternPart == "*" { 346 continue 347 } 348 if patternPart != hostParts[i] { 349 return false 350 } 351 } 352 353 return true 354 } 355 356 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use 357 // an explicitly ASCII function to avoid any sharp corners resulting from 358 // performing Unicode operations on DNS labels. 359 func toLowerCaseASCII(in string) string { 360 // If the string is already lower-case then there's nothing to do. 361 isAlreadyLowerCase := true 362 for _, c := range in { 363 if c == utf8.RuneError { 364 // If we get a UTF-8 error then there might be 365 // upper-case ASCII bytes in the invalid sequence. 366 isAlreadyLowerCase = false 367 break 368 } 369 if 'A' <= c && c <= 'Z' { 370 isAlreadyLowerCase = false 371 break 372 } 373 } 374 375 if isAlreadyLowerCase { 376 return in 377 } 378 379 out := []byte(in) 380 for i, c := range out { 381 if 'A' <= c && c <= 'Z' { 382 out[i] += 'a' - 'A' 383 } 384 } 385 return string(out) 386 } 387 388 // VerifyHostname returns nil if c is a valid certificate for the named host. 389 // Otherwise it returns an error describing the mismatch. 390 func (c *Certificate) VerifyHostname(h string) error { 391 // IP addresses may be written in [ ]. 392 candidateIP := h 393 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { 394 candidateIP = h[1 : len(h)-1] 395 } 396 if ip := net.ParseIP(candidateIP); ip != nil { 397 // We only match IP addresses against IP SANs. 398 // https://tools.ietf.org/html/rfc6125#appendix-B.2 399 for _, candidate := range c.IPAddresses { 400 if ip.Equal(candidate) { 401 return nil 402 } 403 } 404 return HostnameError{c, candidateIP} 405 } 406 407 lowered := toLowerCaseASCII(h) 408 409 if len(c.DNSNames) > 0 { 410 for _, match := range c.DNSNames { 411 if matchHostnames(toLowerCaseASCII(match), lowered) { 412 return nil 413 } 414 } 415 // If Subject Alt Name is given, we ignore the common name. 416 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { 417 return nil 418 } 419 420 return HostnameError{c, h} 421 } 422 423 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { 424 usages := make([]ExtKeyUsage, len(keyUsages)) 425 copy(usages, keyUsages) 426 427 if len(chain) == 0 { 428 return false 429 } 430 431 usagesRemaining := len(usages) 432 433 // We walk down the list and cross out any usages that aren't supported 434 // by each certificate. If we cross out all the usages, then the chain 435 // is unacceptable. 436 437 NextCert: 438 for i := len(chain) - 1; i >= 0; i-- { 439 cert := chain[i] 440 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { 441 // The certificate doesn't have any extended key usage specified. 442 continue 443 } 444 445 for _, usage := range cert.ExtKeyUsage { 446 if usage == ExtKeyUsageAny { 447 // The certificate is explicitly good for any usage. 448 continue NextCert 449 } 450 } 451 452 const invalidUsage ExtKeyUsage = -1 453 454 NextRequestedUsage: 455 for i, requestedUsage := range usages { 456 if requestedUsage == invalidUsage { 457 continue 458 } 459 460 for _, usage := range cert.ExtKeyUsage { 461 if requestedUsage == usage { 462 continue NextRequestedUsage 463 } else if requestedUsage == ExtKeyUsageServerAuth && 464 (usage == ExtKeyUsageNetscapeServerGatedCrypto || 465 usage == ExtKeyUsageMicrosoftServerGatedCrypto) { 466 // In order to support COMODO 467 // certificate chains, we have to 468 // accept Netscape or Microsoft SGC 469 // usages as equal to ServerAuth. 470 continue NextRequestedUsage 471 } 472 } 473 474 usages[i] = invalidUsage 475 usagesRemaining-- 476 if usagesRemaining == 0 { 477 return false 478 } 479 } 480 } 481 482 return true 483 }