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