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