github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 var candidateChains [][]*Certificate 266 if opts.Roots.contains(c) { 267 candidateChains = append(candidateChains, []*Certificate{c}) 268 } else { 269 if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil { 270 return nil, err 271 } 272 } 273 274 keyUsages := opts.KeyUsages 275 if len(keyUsages) == 0 { 276 keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} 277 } 278 279 // If any key usage is acceptable then we're done. 280 for _, usage := range keyUsages { 281 if usage == ExtKeyUsageAny { 282 chains = candidateChains 283 return 284 } 285 } 286 287 for _, candidate := range candidateChains { 288 if checkChainForKeyUsage(candidate, keyUsages) { 289 chains = append(chains, candidate) 290 } 291 } 292 293 if len(chains) == 0 { 294 err = CertificateInvalidError{c, IncompatibleUsage} 295 } 296 297 return 298 } 299 300 func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { 301 n := make([]*Certificate, len(chain)+1) 302 copy(n, chain) 303 n[len(chain)] = cert 304 return n 305 } 306 307 func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) { 308 possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c) 309 for _, rootNum := range possibleRoots { 310 root := opts.Roots.certs[rootNum] 311 err = root.isValid(rootCertificate, currentChain, opts) 312 if err != nil { 313 continue 314 } 315 chains = append(chains, appendToFreshChain(currentChain, root)) 316 } 317 318 possibleIntermediates, failedIntermediate, intermediateErr := opts.Intermediates.findVerifiedParents(c) 319 nextIntermediate: 320 for _, intermediateNum := range possibleIntermediates { 321 intermediate := opts.Intermediates.certs[intermediateNum] 322 for _, cert := range currentChain { 323 if cert == intermediate { 324 continue nextIntermediate 325 } 326 } 327 err = intermediate.isValid(intermediateCertificate, currentChain, opts) 328 if err != nil { 329 continue 330 } 331 var childChains [][]*Certificate 332 childChains, ok := cache[intermediateNum] 333 if !ok { 334 childChains, err = intermediate.buildChains(cache, appendToFreshChain(currentChain, intermediate), opts) 335 cache[intermediateNum] = childChains 336 } 337 chains = append(chains, childChains...) 338 } 339 340 if len(chains) > 0 { 341 err = nil 342 } 343 344 if len(chains) == 0 && err == nil { 345 hintErr := rootErr 346 hintCert := failedRoot 347 if hintErr == nil { 348 hintErr = intermediateErr 349 hintCert = failedIntermediate 350 } 351 err = UnknownAuthorityError{c, hintErr, hintCert} 352 } 353 354 return 355 } 356 357 func matchHostnames(pattern, host string) bool { 358 host = strings.TrimSuffix(host, ".") 359 pattern = strings.TrimSuffix(pattern, ".") 360 361 if len(pattern) == 0 || len(host) == 0 { 362 return false 363 } 364 365 patternParts := strings.Split(pattern, ".") 366 hostParts := strings.Split(host, ".") 367 368 if len(patternParts) != len(hostParts) { 369 return false 370 } 371 372 for i, patternPart := range patternParts { 373 if i == 0 && patternPart == "*" { 374 continue 375 } 376 if patternPart != hostParts[i] { 377 return false 378 } 379 } 380 381 return true 382 } 383 384 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use 385 // an explicitly ASCII function to avoid any sharp corners resulting from 386 // performing Unicode operations on DNS labels. 387 func toLowerCaseASCII(in string) string { 388 // If the string is already lower-case then there's nothing to do. 389 isAlreadyLowerCase := true 390 for _, c := range in { 391 if c == utf8.RuneError { 392 // If we get a UTF-8 error then there might be 393 // upper-case ASCII bytes in the invalid sequence. 394 isAlreadyLowerCase = false 395 break 396 } 397 if 'A' <= c && c <= 'Z' { 398 isAlreadyLowerCase = false 399 break 400 } 401 } 402 403 if isAlreadyLowerCase { 404 return in 405 } 406 407 out := []byte(in) 408 for i, c := range out { 409 if 'A' <= c && c <= 'Z' { 410 out[i] += 'a' - 'A' 411 } 412 } 413 return string(out) 414 } 415 416 // VerifyHostname returns nil if c is a valid certificate for the named host. 417 // Otherwise it returns an error describing the mismatch. 418 func (c *Certificate) VerifyHostname(h string) error { 419 // IP addresses may be written in [ ]. 420 candidateIP := h 421 if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { 422 candidateIP = h[1 : len(h)-1] 423 } 424 if ip := net.ParseIP(candidateIP); ip != nil { 425 // We only match IP addresses against IP SANs. 426 // https://tools.ietf.org/html/rfc6125#appendix-B.2 427 for _, candidate := range c.IPAddresses { 428 if ip.Equal(candidate) { 429 return nil 430 } 431 } 432 return HostnameError{c, candidateIP} 433 } 434 435 lowered := toLowerCaseASCII(h) 436 437 if len(c.DNSNames) > 0 { 438 for _, match := range c.DNSNames { 439 if matchHostnames(toLowerCaseASCII(match), lowered) { 440 return nil 441 } 442 } 443 // If Subject Alt Name is given, we ignore the common name. 444 } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { 445 return nil 446 } 447 448 return HostnameError{c, h} 449 } 450 451 func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { 452 usages := make([]ExtKeyUsage, len(keyUsages)) 453 copy(usages, keyUsages) 454 455 if len(chain) == 0 { 456 return false 457 } 458 459 usagesRemaining := len(usages) 460 461 // We walk down the list and cross out any usages that aren't supported 462 // by each certificate. If we cross out all the usages, then the chain 463 // is unacceptable. 464 465 NextCert: 466 for i := len(chain) - 1; i >= 0; i-- { 467 cert := chain[i] 468 if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { 469 // The certificate doesn't have any extended key usage specified. 470 continue 471 } 472 473 for _, usage := range cert.ExtKeyUsage { 474 if usage == ExtKeyUsageAny { 475 // The certificate is explicitly good for any usage. 476 continue NextCert 477 } 478 } 479 480 const invalidUsage ExtKeyUsage = -1 481 482 NextRequestedUsage: 483 for i, requestedUsage := range usages { 484 if requestedUsage == invalidUsage { 485 continue 486 } 487 488 for _, usage := range cert.ExtKeyUsage { 489 if requestedUsage == usage { 490 continue NextRequestedUsage 491 } else if requestedUsage == ExtKeyUsageServerAuth && 492 (usage == ExtKeyUsageNetscapeServerGatedCrypto || 493 usage == ExtKeyUsageMicrosoftServerGatedCrypto) { 494 // In order to support COMODO 495 // certificate chains, we have to 496 // accept Netscape or Microsoft SGC 497 // usages as equal to ServerAuth. 498 continue NextRequestedUsage 499 } 500 } 501 502 usages[i] = invalidUsage 503 usagesRemaining-- 504 if usagesRemaining == 0 { 505 return false 506 } 507 } 508 } 509 510 return true 511 }