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