get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/ocsp.go (about) 1 // Copyright 2021-2023 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "bytes" 18 "crypto/sha256" 19 "crypto/tls" 20 "crypto/x509" 21 "encoding/asn1" 22 "encoding/base64" 23 "encoding/pem" 24 "errors" 25 "fmt" 26 "io" 27 "net/http" 28 "os" 29 "path/filepath" 30 "strings" 31 "sync" 32 "time" 33 34 "golang.org/x/crypto/ocsp" 35 36 "get.pme.sh/pnats/server/certidp" 37 "get.pme.sh/pnats/server/certstore" 38 ) 39 40 const ( 41 defaultOCSPStoreDir = "ocsp" 42 defaultOCSPCheckInterval = 24 * time.Hour 43 minOCSPCheckInterval = 2 * time.Minute 44 ) 45 46 type OCSPMode uint8 47 48 const ( 49 // OCSPModeAuto staples a status, only if "status_request" is set in cert. 50 OCSPModeAuto OCSPMode = iota 51 52 // OCSPModeAlways enforces OCSP stapling for certs and shuts down the server in 53 // case a server is revoked or cannot get OCSP staples. 54 OCSPModeAlways 55 56 // OCSPModeNever disables OCSP stapling even if cert has Must-Staple flag. 57 OCSPModeNever 58 59 // OCSPModeMust honors the Must-Staple flag from a certificate but also causing shutdown 60 // in case the certificate has been revoked. 61 OCSPModeMust 62 ) 63 64 // OCSPMonitor monitors the state of a staple per certificate. 65 type OCSPMonitor struct { 66 kind string 67 mu sync.Mutex 68 raw []byte 69 srv *Server 70 certFile string 71 resp *ocsp.Response 72 hc *http.Client 73 stopCh chan struct{} 74 Leaf *x509.Certificate 75 Issuer *x509.Certificate 76 77 shutdownOnRevoke bool 78 } 79 80 func (oc *OCSPMonitor) getNextRun() time.Duration { 81 oc.mu.Lock() 82 nextUpdate := oc.resp.NextUpdate 83 oc.mu.Unlock() 84 85 now := time.Now() 86 if nextUpdate.IsZero() { 87 // If response is missing NextUpdate, we check the day after. 88 // Technically, if NextUpdate is missing, we can try whenever. 89 // https://tools.ietf.org/html/rfc6960#section-4.2.2.1 90 return defaultOCSPCheckInterval 91 } 92 dur := nextUpdate.Sub(now) / 2 93 94 // If negative, then wait a couple of minutes before getting another staple. 95 if dur < 0 { 96 return minOCSPCheckInterval 97 } 98 99 return dur 100 } 101 102 func (oc *OCSPMonitor) getStatus() ([]byte, *ocsp.Response, error) { 103 raw, resp := oc.getCacheStatus() 104 if len(raw) > 0 && resp != nil { 105 // Check if the OCSP is still valid. 106 if err := validOCSPResponse(resp); err == nil { 107 return raw, resp, nil 108 } 109 } 110 var err error 111 raw, resp, err = oc.getLocalStatus() 112 if err == nil { 113 return raw, resp, nil 114 } 115 116 return oc.getRemoteStatus() 117 } 118 119 func (oc *OCSPMonitor) getCacheStatus() ([]byte, *ocsp.Response) { 120 oc.mu.Lock() 121 defer oc.mu.Unlock() 122 return oc.raw, oc.resp 123 } 124 125 func (oc *OCSPMonitor) getLocalStatus() ([]byte, *ocsp.Response, error) { 126 opts := oc.srv.getOpts() 127 storeDir := opts.StoreDir 128 if storeDir == _EMPTY_ { 129 return nil, nil, fmt.Errorf("store_dir not set") 130 } 131 132 // This key must be based upon the current full certificate, not the public key, 133 // so MUST be on the full raw certificate and not an SPKI or other reduced form. 134 key := fmt.Sprintf("%x", sha256.Sum256(oc.Leaf.Raw)) 135 136 oc.mu.Lock() 137 raw, err := os.ReadFile(filepath.Join(storeDir, defaultOCSPStoreDir, key)) 138 oc.mu.Unlock() 139 if err != nil { 140 return nil, nil, err 141 } 142 143 resp, err := ocsp.ParseResponse(raw, oc.Issuer) 144 if err != nil { 145 return nil, nil, fmt.Errorf("failed to get local status: %w", err) 146 } 147 if err := validOCSPResponse(resp); err != nil { 148 return nil, nil, err 149 } 150 151 // Cache the response. 152 oc.mu.Lock() 153 oc.raw = raw 154 oc.resp = resp 155 oc.mu.Unlock() 156 157 return raw, resp, nil 158 } 159 160 func (oc *OCSPMonitor) getRemoteStatus() ([]byte, *ocsp.Response, error) { 161 opts := oc.srv.getOpts() 162 var overrideURLs []string 163 if config := opts.OCSPConfig; config != nil { 164 overrideURLs = config.OverrideURLs 165 } 166 getRequestBytes := func(u string, reqDER []byte, hc *http.Client) ([]byte, error) { 167 reqEnc := base64.StdEncoding.EncodeToString(reqDER) 168 u = fmt.Sprintf("%s/%s", u, reqEnc) 169 start := time.Now() 170 resp, err := hc.Get(u) 171 if err != nil { 172 return nil, err 173 } 174 defer resp.Body.Close() 175 176 oc.srv.Debugf("Received OCSP response (method=GET, status=%v, url=%s, duration=%.3fs)", 177 resp.StatusCode, u, time.Since(start).Seconds()) 178 if resp.StatusCode > 299 { 179 return nil, fmt.Errorf("non-ok http status on GET request (reqlen=%d): %d", len(reqEnc), resp.StatusCode) 180 } 181 return io.ReadAll(resp.Body) 182 } 183 postRequestBytes := func(u string, body []byte, hc *http.Client) ([]byte, error) { 184 hreq, err := http.NewRequest("POST", u, bytes.NewReader(body)) 185 if err != nil { 186 return nil, err 187 } 188 hreq.Header.Add("Content-Type", "application/ocsp-request") 189 hreq.Header.Add("Accept", "application/ocsp-response") 190 191 start := time.Now() 192 resp, err := hc.Do(hreq) 193 if err != nil { 194 return nil, err 195 } 196 defer resp.Body.Close() 197 198 oc.srv.Debugf("Received OCSP response (method=POST, status=%v, url=%s, duration=%.3fs)", 199 resp.StatusCode, u, time.Since(start).Seconds()) 200 if resp.StatusCode > 299 { 201 return nil, fmt.Errorf("non-ok http status on POST request (reqlen=%d): %d", len(body), resp.StatusCode) 202 } 203 return io.ReadAll(resp.Body) 204 } 205 206 // Request documentation: 207 // https://tools.ietf.org/html/rfc6960#appendix-A.1 208 209 reqDER, err := ocsp.CreateRequest(oc.Leaf, oc.Issuer, nil) 210 if err != nil { 211 return nil, nil, err 212 } 213 214 responders := oc.Leaf.OCSPServer 215 if len(overrideURLs) > 0 { 216 responders = overrideURLs 217 } 218 if len(responders) == 0 { 219 return nil, nil, fmt.Errorf("no available ocsp servers") 220 } 221 222 oc.mu.Lock() 223 hc := oc.hc 224 oc.mu.Unlock() 225 226 var raw []byte 227 for _, u := range responders { 228 var postErr, getErr error 229 u = strings.TrimSuffix(u, "/") 230 // Prefer to make POST requests first. 231 raw, postErr = postRequestBytes(u, reqDER, hc) 232 if postErr == nil { 233 err = nil 234 break 235 } else { 236 // Fallback to use a GET request. 237 raw, getErr = getRequestBytes(u, reqDER, hc) 238 if getErr == nil { 239 err = nil 240 break 241 } else { 242 err = errors.Join(postErr, getErr) 243 } 244 } 245 } 246 if err != nil { 247 return nil, nil, fmt.Errorf("exhausted ocsp servers: %w", err) 248 } 249 resp, err := ocsp.ParseResponse(raw, oc.Issuer) 250 if err != nil { 251 return nil, nil, fmt.Errorf("failed to get remote status: %w", err) 252 } 253 if err := validOCSPResponse(resp); err != nil { 254 return nil, nil, err 255 } 256 257 if storeDir := opts.StoreDir; storeDir != _EMPTY_ { 258 key := fmt.Sprintf("%x", sha256.Sum256(oc.Leaf.Raw)) 259 if err := oc.writeOCSPStatus(storeDir, key, raw); err != nil { 260 return nil, nil, fmt.Errorf("failed to write ocsp status: %w", err) 261 } 262 } 263 264 oc.mu.Lock() 265 oc.raw = raw 266 oc.resp = resp 267 oc.mu.Unlock() 268 269 return raw, resp, nil 270 } 271 272 func (oc *OCSPMonitor) run() { 273 s := oc.srv 274 s.mu.Lock() 275 quitCh := s.quitCh 276 s.mu.Unlock() 277 278 var doShutdown bool 279 defer func() { 280 // Need to decrement before shuting down, otherwise shutdown 281 // would be stuck waiting on grWG to go down to 0. 282 s.grWG.Done() 283 if doShutdown { 284 s.Shutdown() 285 } 286 }() 287 288 oc.mu.Lock() 289 shutdownOnRevoke := oc.shutdownOnRevoke 290 certFile := oc.certFile 291 stopCh := oc.stopCh 292 kind := oc.kind 293 oc.mu.Unlock() 294 295 var nextRun time.Duration 296 _, resp, err := oc.getStatus() 297 if err == nil && resp.Status == ocsp.Good { 298 nextRun = oc.getNextRun() 299 t := resp.NextUpdate.Format(time.RFC3339Nano) 300 s.Noticef( 301 "Found OCSP status for %s certificate at '%s': good, next update %s, checking again in %s", 302 kind, certFile, t, nextRun, 303 ) 304 } else if err == nil && shutdownOnRevoke { 305 // If resp.Status is ocsp.Revoked, ocsp.Unknown, or any other value. 306 s.Errorf("Found OCSP status for %s certificate at '%s': %s", kind, certFile, ocspStatusString(resp.Status)) 307 doShutdown = true 308 return 309 } 310 311 for { 312 // On reload, if the certificate changes then need to stop this monitor. 313 select { 314 case <-time.After(nextRun): 315 case <-stopCh: 316 // In case of reload and have to restart the OCSP stapling monitoring. 317 return 318 case <-quitCh: 319 // Server quit channel. 320 return 321 } 322 _, resp, err := oc.getRemoteStatus() 323 if err != nil { 324 nextRun = oc.getNextRun() 325 s.Errorf("Bad OCSP status update for certificate '%s': %s, trying again in %v", certFile, err, nextRun) 326 continue 327 } 328 329 switch n := resp.Status; n { 330 case ocsp.Good: 331 nextRun = oc.getNextRun() 332 t := resp.NextUpdate.Format(time.RFC3339Nano) 333 s.Noticef( 334 "Received OCSP status for %s certificate '%s': good, next update %s, checking again in %s", 335 kind, certFile, t, nextRun, 336 ) 337 continue 338 default: 339 s.Errorf("Received OCSP status for %s certificate '%s': %s", kind, certFile, ocspStatusString(n)) 340 if shutdownOnRevoke { 341 doShutdown = true 342 } 343 return 344 } 345 } 346 } 347 348 func (oc *OCSPMonitor) stop() { 349 oc.mu.Lock() 350 stopCh := oc.stopCh 351 oc.mu.Unlock() 352 stopCh <- struct{}{} 353 } 354 355 // NewOCSPMonitor takes a TLS configuration then wraps it with the callbacks set for OCSP verification 356 // along with a monitor that will periodically fetch OCSP staples. 357 func (srv *Server) NewOCSPMonitor(config *tlsConfigKind) (*tls.Config, *OCSPMonitor, error) { 358 kind := config.kind 359 tc := config.tlsConfig 360 tcOpts := config.tlsOpts 361 opts := srv.getOpts() 362 oc := opts.OCSPConfig 363 364 // We need to track the CA certificate in case the CA is not present 365 // in the chain to be able to verify the signature of the OCSP staple. 366 var ( 367 certFile string 368 caFile string 369 ) 370 if kind == kindStringMap[CLIENT] { 371 tcOpts = opts.tlsConfigOpts 372 if opts.TLSCert != _EMPTY_ { 373 certFile = opts.TLSCert 374 } 375 if opts.TLSCaCert != _EMPTY_ { 376 caFile = opts.TLSCaCert 377 } 378 } 379 if tcOpts != nil { 380 certFile = tcOpts.CertFile 381 caFile = tcOpts.CaFile 382 } 383 384 // NOTE: Currently OCSP Stapling is enabled only for the first certificate found. 385 var mon *OCSPMonitor 386 for _, currentCert := range tc.Certificates { 387 // Create local copy since this will be used in the GetCertificate callback. 388 cert := currentCert 389 390 // This is normally non-nil, but can still be nil here when in tests 391 // or in some embedded scenarios. 392 if cert.Leaf == nil { 393 if len(cert.Certificate) <= 0 { 394 return nil, nil, fmt.Errorf("no certificate found") 395 } 396 var err error 397 cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) 398 if err != nil { 399 return nil, nil, fmt.Errorf("error parsing certificate: %v", err) 400 } 401 } 402 var shutdownOnRevoke bool 403 mustStaple := hasOCSPStatusRequest(cert.Leaf) 404 if oc != nil { 405 switch { 406 case oc.Mode == OCSPModeNever: 407 if mustStaple { 408 srv.Warnf("Certificate at '%s' has MustStaple but OCSP is disabled", certFile) 409 } 410 return tc, nil, nil 411 case oc.Mode == OCSPModeAlways: 412 // Start the monitor for this cert even if it does not have 413 // the MustStaple flag and shutdown the server in case the 414 // staple ever gets revoked. 415 mustStaple = true 416 shutdownOnRevoke = true 417 case oc.Mode == OCSPModeMust && mustStaple: 418 shutdownOnRevoke = true 419 case oc.Mode == OCSPModeAuto && !mustStaple: 420 // "status_request" MustStaple flag not set in certificate. No need to do anything. 421 return tc, nil, nil 422 } 423 } 424 if !mustStaple { 425 // No explicit OCSP config and cert does not have MustStaple flag either. 426 return tc, nil, nil 427 } 428 429 if err := srv.setupOCSPStapleStoreDir(); err != nil { 430 return nil, nil, err 431 } 432 433 // TODO: Add OCSP 'responder_cert' option in case CA cert not available. 434 issuer, err := getOCSPIssuer(caFile, cert.Certificate) 435 if err != nil { 436 return nil, nil, err 437 } 438 439 mon = &OCSPMonitor{ 440 kind: kind, 441 srv: srv, 442 hc: &http.Client{Timeout: 30 * time.Second}, 443 shutdownOnRevoke: shutdownOnRevoke, 444 certFile: certFile, 445 stopCh: make(chan struct{}, 1), 446 Leaf: cert.Leaf, 447 Issuer: issuer, 448 } 449 450 // Get the certificate status from the memory, then remote OCSP responder. 451 if _, resp, err := mon.getStatus(); err != nil { 452 return nil, nil, fmt.Errorf("bad OCSP status update for certificate at '%s': %s", certFile, err) 453 } else if err == nil && resp != nil && resp.Status != ocsp.Good && shutdownOnRevoke { 454 return nil, nil, fmt.Errorf("found existing OCSP status for certificate at '%s': %s", certFile, ocspStatusString(resp.Status)) 455 } 456 457 // Callbacks below will be in charge of returning the certificate instead, 458 // so this has to be nil. 459 tc.Certificates = nil 460 461 // GetCertificate returns a certificate that's presented to a client. 462 tc.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { 463 raw, _, err := mon.getStatus() 464 if err != nil { 465 return nil, err 466 } 467 468 return &tls.Certificate{ 469 OCSPStaple: raw, 470 Certificate: cert.Certificate, 471 PrivateKey: cert.PrivateKey, 472 SupportedSignatureAlgorithms: cert.SupportedSignatureAlgorithms, 473 SignedCertificateTimestamps: cert.SignedCertificateTimestamps, 474 Leaf: cert.Leaf, 475 }, nil 476 } 477 478 // Check whether need to verify staples from a peer router or gateway connection. 479 switch kind { 480 case kindStringMap[ROUTER], kindStringMap[GATEWAY]: 481 tc.VerifyConnection = func(s tls.ConnectionState) error { 482 oresp := s.OCSPResponse 483 if oresp == nil { 484 return fmt.Errorf("%s peer missing OCSP Staple", kind) 485 } 486 487 // Peer connections will verify the response of the staple. 488 if len(s.VerifiedChains) == 0 { 489 return fmt.Errorf("%s peer missing TLS verified chains", kind) 490 } 491 492 chain := s.VerifiedChains[0] 493 peerLeaf := chain[0] 494 peerIssuer := certidp.GetLeafIssuerCert(chain, 0) 495 if peerIssuer == nil { 496 return fmt.Errorf("failed to get issuer certificate for %s peer", kind) 497 } 498 499 // Response signature of issuer or issuer delegate is checked in the library parse 500 resp, err := ocsp.ParseResponseForCert(oresp, peerLeaf, peerIssuer) 501 if err != nil { 502 return fmt.Errorf("failed to parse OCSP response from %s peer: %w", kind, err) 503 } 504 505 // If signer was issuer delegate double-check issuer delegate authorization 506 if resp.Certificate != nil { 507 ok := false 508 for _, eku := range resp.Certificate.ExtKeyUsage { 509 if eku == x509.ExtKeyUsageOCSPSigning { 510 ok = true 511 break 512 } 513 } 514 if !ok { 515 return fmt.Errorf("OCSP staple's signer missing authorization by CA to act as OCSP signer") 516 } 517 } 518 519 // Check that the OCSP response is effective, take defaults for clockskew and default validity 520 peerOpts := certidp.OCSPPeerConfig{ClockSkew: -1, TTLUnsetNextUpdate: -1} 521 sLog := certidp.Log{Debugf: srv.Debugf} 522 if !certidp.OCSPResponseCurrent(resp, &peerOpts, &sLog) { 523 return fmt.Errorf("OCSP staple from %s peer not current", kind) 524 } 525 526 if resp.Status != ocsp.Good { 527 return fmt.Errorf("bad status for OCSP Staple from %s peer: %s", kind, ocspStatusString(resp.Status)) 528 } 529 530 return nil 531 } 532 533 // When server makes a peer connection, need to also present an OCSP Staple. 534 tc.GetClientCertificate = func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { 535 raw, _, err := mon.getStatus() 536 if err != nil { 537 return nil, err 538 } 539 cert.OCSPStaple = raw 540 541 return &cert, nil 542 } 543 default: 544 // GetClientCertificate returns a certificate that's presented to a server. 545 tc.GetClientCertificate = func(info *tls.CertificateRequestInfo) (*tls.Certificate, error) { 546 return &cert, nil 547 } 548 } 549 550 } 551 return tc, mon, nil 552 } 553 554 func (s *Server) setupOCSPStapleStoreDir() error { 555 opts := s.getOpts() 556 storeDir := opts.StoreDir 557 if storeDir == _EMPTY_ { 558 return nil 559 } 560 storeDir = filepath.Join(storeDir, defaultOCSPStoreDir) 561 if stat, err := os.Stat(storeDir); os.IsNotExist(err) { 562 if err := os.MkdirAll(storeDir, defaultDirPerms); err != nil { 563 return fmt.Errorf("could not create OCSP storage directory - %v", err) 564 } 565 } else if stat == nil || !stat.IsDir() { 566 return fmt.Errorf("OCSP storage directory is not a directory") 567 } 568 return nil 569 } 570 571 type tlsConfigKind struct { 572 tlsConfig *tls.Config 573 tlsOpts *TLSConfigOpts 574 kind string 575 isLeafSpoke bool 576 apply func(*tls.Config) 577 } 578 579 func (s *Server) configureOCSP() []*tlsConfigKind { 580 sopts := s.getOpts() 581 582 configs := make([]*tlsConfigKind, 0) 583 584 if config := sopts.TLSConfig; config != nil { 585 opts := sopts.tlsConfigOpts 586 o := &tlsConfigKind{ 587 kind: kindStringMap[CLIENT], 588 tlsConfig: config, 589 tlsOpts: opts, 590 apply: func(tc *tls.Config) { sopts.TLSConfig = tc }, 591 } 592 configs = append(configs, o) 593 } 594 if config := sopts.Websocket.TLSConfig; config != nil { 595 opts := sopts.Websocket.tlsConfigOpts 596 o := &tlsConfigKind{ 597 kind: kindStringMap[CLIENT], 598 tlsConfig: config, 599 tlsOpts: opts, 600 apply: func(tc *tls.Config) { sopts.Websocket.TLSConfig = tc }, 601 } 602 configs = append(configs, o) 603 } 604 if config := sopts.MQTT.TLSConfig; config != nil { 605 opts := sopts.tlsConfigOpts 606 o := &tlsConfigKind{ 607 kind: kindStringMap[CLIENT], 608 tlsConfig: config, 609 tlsOpts: opts, 610 apply: func(tc *tls.Config) { sopts.MQTT.TLSConfig = tc }, 611 } 612 configs = append(configs, o) 613 } 614 if config := sopts.Cluster.TLSConfig; config != nil { 615 opts := sopts.Cluster.tlsConfigOpts 616 o := &tlsConfigKind{ 617 kind: kindStringMap[ROUTER], 618 tlsConfig: config, 619 tlsOpts: opts, 620 apply: func(tc *tls.Config) { sopts.Cluster.TLSConfig = tc }, 621 } 622 configs = append(configs, o) 623 } 624 if config := sopts.LeafNode.TLSConfig; config != nil { 625 opts := sopts.LeafNode.tlsConfigOpts 626 o := &tlsConfigKind{ 627 kind: kindStringMap[LEAF], 628 tlsConfig: config, 629 tlsOpts: opts, 630 apply: func(tc *tls.Config) { sopts.LeafNode.TLSConfig = tc }, 631 } 632 configs = append(configs, o) 633 } 634 for _, remote := range sopts.LeafNode.Remotes { 635 if config := remote.TLSConfig; config != nil { 636 // Use a copy of the remote here since will be used 637 // in the apply func callback below. 638 r, opts := remote, remote.tlsConfigOpts 639 o := &tlsConfigKind{ 640 kind: kindStringMap[LEAF], 641 tlsConfig: config, 642 tlsOpts: opts, 643 isLeafSpoke: true, 644 apply: func(tc *tls.Config) { r.TLSConfig = tc }, 645 } 646 configs = append(configs, o) 647 } 648 } 649 if config := sopts.Gateway.TLSConfig; config != nil { 650 opts := sopts.Gateway.tlsConfigOpts 651 o := &tlsConfigKind{ 652 kind: kindStringMap[GATEWAY], 653 tlsConfig: config, 654 tlsOpts: opts, 655 apply: func(tc *tls.Config) { sopts.Gateway.TLSConfig = tc }, 656 } 657 configs = append(configs, o) 658 } 659 for _, remote := range sopts.Gateway.Gateways { 660 if config := remote.TLSConfig; config != nil { 661 gw, opts := remote, remote.tlsConfigOpts 662 o := &tlsConfigKind{ 663 kind: kindStringMap[GATEWAY], 664 tlsConfig: config, 665 tlsOpts: opts, 666 apply: func(tc *tls.Config) { gw.TLSConfig = tc }, 667 } 668 configs = append(configs, o) 669 } 670 } 671 return configs 672 } 673 674 func (s *Server) enableOCSP() error { 675 configs := s.configureOCSP() 676 677 for _, config := range configs { 678 679 // We do not staple Leaf Hub and Leaf Spokes, use ocsp_peer 680 if config.kind != kindStringMap[LEAF] { 681 // OCSP Stapling feature, will also enable tls server peer check for gateway and route peers 682 tc, mon, err := s.NewOCSPMonitor(config) 683 if err != nil { 684 return err 685 } 686 // Check if an OCSP stapling monitor is required for this certificate. 687 if mon != nil { 688 s.ocsps = append(s.ocsps, mon) 689 690 // Override the TLS config with one that follows OCSP stapling 691 config.apply(tc) 692 } 693 } 694 695 // OCSP peer check (client mTLS, leaf mTLS, leaf remote TLS) 696 if config.kind == kindStringMap[CLIENT] || config.kind == kindStringMap[LEAF] { 697 tc, plugged, err := s.plugTLSOCSPPeer(config) 698 if err != nil { 699 return err 700 } 701 if plugged && tc != nil { 702 s.ocspPeerVerify = true 703 config.apply(tc) 704 } 705 } 706 } 707 708 return nil 709 } 710 711 func (s *Server) startOCSPMonitoring() { 712 s.mu.Lock() 713 ocsps := s.ocsps 714 s.mu.Unlock() 715 if ocsps == nil { 716 return 717 } 718 for _, mon := range ocsps { 719 m := mon 720 m.mu.Lock() 721 kind := m.kind 722 m.mu.Unlock() 723 s.Noticef("OCSP Stapling enabled for %s connections", kind) 724 s.startGoRoutine(func() { m.run() }) 725 } 726 } 727 728 func (s *Server) reloadOCSP() error { 729 if err := s.setupOCSPStapleStoreDir(); err != nil { 730 return err 731 } 732 733 s.mu.Lock() 734 ocsps := s.ocsps 735 s.mu.Unlock() 736 737 // Stop all OCSP Stapling monitors in case there were any running. 738 for _, oc := range ocsps { 739 oc.stop() 740 } 741 742 configs := s.configureOCSP() 743 744 // Restart the monitors under the new configuration. 745 ocspm := make([]*OCSPMonitor, 0) 746 747 // Reset server's ocspPeerVerify flag to re-detect at least one plugged OCSP peer 748 s.mu.Lock() 749 s.ocspPeerVerify = false 750 s.mu.Unlock() 751 s.stopOCSPResponseCache() 752 753 for _, config := range configs { 754 // We do not staple Leaf Hub and Leaf Spokes, use ocsp_peer 755 if config.kind != kindStringMap[LEAF] { 756 tc, mon, err := s.NewOCSPMonitor(config) 757 if err != nil { 758 return err 759 } 760 // Check if an OCSP stapling monitor is required for this certificate. 761 if mon != nil { 762 ocspm = append(ocspm, mon) 763 764 // Apply latest TLS configuration. 765 config.apply(tc) 766 } 767 } 768 769 // OCSP peer check (client mTLS, leaf mTLS, leaf remote TLS) 770 if config.kind == kindStringMap[CLIENT] || config.kind == kindStringMap[LEAF] { 771 tc, plugged, err := s.plugTLSOCSPPeer(config) 772 if err != nil { 773 return err 774 } 775 if plugged && tc != nil { 776 s.ocspPeerVerify = true 777 config.apply(tc) 778 } 779 } 780 } 781 782 // Replace stopped monitors with the new ones. 783 s.mu.Lock() 784 s.ocsps = ocspm 785 s.mu.Unlock() 786 787 // Dispatch all goroutines once again. 788 s.startOCSPMonitoring() 789 790 // Init and restart OCSP responder cache 791 s.stopOCSPResponseCache() 792 s.initOCSPResponseCache() 793 s.startOCSPResponseCache() 794 795 return nil 796 } 797 798 func hasOCSPStatusRequest(cert *x509.Certificate) bool { 799 // OID for id-pe-tlsfeature defined in RFC here: 800 // https://datatracker.ietf.org/doc/html/rfc7633 801 tlsFeatures := asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 24} 802 const statusRequestExt = 5 803 804 // Example values: 805 // * [48 3 2 1 5] - seen when creating own certs locally 806 // * [30 3 2 1 5] - seen in the wild 807 // Documentation: 808 // https://tools.ietf.org/html/rfc6066 809 810 for _, ext := range cert.Extensions { 811 if !ext.Id.Equal(tlsFeatures) { 812 continue 813 } 814 815 var val []int 816 rest, err := asn1.Unmarshal(ext.Value, &val) 817 if err != nil || len(rest) > 0 { 818 return false 819 } 820 821 for _, n := range val { 822 if n == statusRequestExt { 823 return true 824 } 825 } 826 break 827 } 828 829 return false 830 } 831 832 // writeOCSPStatus writes an OCSP status to a temporary file then moves it to a 833 // new path, in an attempt to avoid corrupting existing data. 834 func (oc *OCSPMonitor) writeOCSPStatus(storeDir, file string, data []byte) error { 835 storeDir = filepath.Join(storeDir, defaultOCSPStoreDir) 836 tmp, err := os.CreateTemp(storeDir, "tmp-cert-status") 837 if err != nil { 838 return err 839 } 840 841 if _, err := tmp.Write(data); err != nil { 842 tmp.Close() 843 os.Remove(tmp.Name()) 844 return err 845 } 846 if err := tmp.Close(); err != nil { 847 return err 848 } 849 850 oc.mu.Lock() 851 err = os.Rename(tmp.Name(), filepath.Join(storeDir, file)) 852 oc.mu.Unlock() 853 if err != nil { 854 os.Remove(tmp.Name()) 855 return err 856 } 857 858 return nil 859 } 860 861 func parseCertPEM(name string) ([]*x509.Certificate, error) { 862 data, err := os.ReadFile(name) 863 if err != nil { 864 return nil, err 865 } 866 867 var pemBytes []byte 868 869 var block *pem.Block 870 for len(data) != 0 { 871 block, data = pem.Decode(data) 872 if block == nil { 873 break 874 } 875 if block.Type != "CERTIFICATE" { 876 return nil, fmt.Errorf("unexpected PEM certificate type: %s", block.Type) 877 } 878 879 pemBytes = append(pemBytes, block.Bytes...) 880 } 881 882 return x509.ParseCertificates(pemBytes) 883 } 884 885 // getOCSPIssuerLocally determines a leaf's issuer from locally configured certificates 886 func getOCSPIssuerLocally(trustedCAs []*x509.Certificate, certBundle []*x509.Certificate) (*x509.Certificate, error) { 887 var vOpts x509.VerifyOptions 888 var leaf *x509.Certificate 889 trustedCAPool := x509.NewCertPool() 890 891 // Require Leaf as first cert in bundle 892 if len(certBundle) > 0 { 893 leaf = certBundle[0] 894 } else { 895 return nil, fmt.Errorf("invalid ocsp ca configuration") 896 } 897 898 // Allow Issuer to be configured as second cert in bundle 899 if len(certBundle) > 1 { 900 // The operator may have misconfigured the cert bundle 901 issuerCandidate := certBundle[1] 902 err := issuerCandidate.CheckSignature(leaf.SignatureAlgorithm, leaf.RawTBSCertificate, leaf.Signature) 903 if err != nil { 904 return nil, fmt.Errorf("invalid issuer configuration: %w", err) 905 } else { 906 return issuerCandidate, nil 907 } 908 } 909 910 // Operator did not provide the Leaf Issuer in cert bundle second position 911 // so we will attempt to create at least one ordered verified chain from the 912 // trusted CA pool. 913 914 // Specify CA trust store to validator; if unset, system trust store used 915 if len(trustedCAs) > 0 { 916 for _, ca := range trustedCAs { 917 trustedCAPool.AddCert(ca) 918 } 919 vOpts.Roots = trustedCAPool 920 } 921 922 return certstore.GetLeafIssuer(leaf, vOpts), nil 923 } 924 925 // getOCSPIssuer determines an issuer certificate from the cert (bundle) or the file-based CA trust store 926 func getOCSPIssuer(caFile string, chain [][]byte) (*x509.Certificate, error) { 927 var issuer *x509.Certificate 928 var trustedCAs []*x509.Certificate 929 var certBundle []*x509.Certificate 930 var err error 931 932 // FIXME(tgb): extend if pluggable CA store provider added to NATS (i.e. other than PEM file) 933 934 // Non-system default CA trust store passed 935 if caFile != _EMPTY_ { 936 trustedCAs, err = parseCertPEM(caFile) 937 if err != nil { 938 return nil, fmt.Errorf("failed to parse ca_file: %v", err) 939 } 940 } 941 942 // Specify bundled intermediate CA store 943 for _, certBytes := range chain { 944 cert, err := x509.ParseCertificate(certBytes) 945 if err != nil { 946 return nil, fmt.Errorf("failed to parse cert: %v", err) 947 } 948 certBundle = append(certBundle, cert) 949 } 950 951 issuer, err = getOCSPIssuerLocally(trustedCAs, certBundle) 952 if err != nil || issuer == nil { 953 return nil, fmt.Errorf("no issuers found") 954 } 955 956 if !issuer.IsCA { 957 return nil, fmt.Errorf("%s invalid ca basic constraints: is not ca", issuer.Subject) 958 } 959 return issuer, nil 960 } 961 962 func ocspStatusString(n int) string { 963 switch n { 964 case ocsp.Good: 965 return "good" 966 case ocsp.Revoked: 967 return "revoked" 968 default: 969 return "unknown" 970 } 971 } 972 973 func validOCSPResponse(r *ocsp.Response) error { 974 // Time validation not handled by ParseResponse. 975 // https://tools.ietf.org/html/rfc6960#section-4.2.2.1 976 if !r.NextUpdate.IsZero() && r.NextUpdate.Before(time.Now()) { 977 t := r.NextUpdate.Format(time.RFC3339Nano) 978 return fmt.Errorf("invalid ocsp NextUpdate, is past time: %s", t) 979 } 980 if r.ThisUpdate.After(time.Now()) { 981 t := r.ThisUpdate.Format(time.RFC3339Nano) 982 return fmt.Errorf("invalid ocsp ThisUpdate, is future time: %s", t) 983 } 984 985 return nil 986 }