decred.org/dcrwallet/v3@v3.1.0/rpcserver.go (about) 1 // Copyright (c) 2013-2015 The btcsuite developers 2 // Copyright (c) 2015-2020 The Decred developers 3 // Use of this source code is governed by an ISC 4 // license that can be found in the LICENSE file. 5 6 package main 7 8 import ( 9 "bytes" 10 "context" 11 "crypto/rand" 12 "crypto/tls" 13 "crypto/x509" 14 "crypto/x509/pkix" 15 "encoding/pem" 16 "fmt" 17 "math/big" 18 "net" 19 "os" 20 "path/filepath" 21 "runtime" 22 "strings" 23 "time" 24 25 "decred.org/dcrwallet/v3/errors" 26 "decred.org/dcrwallet/v3/internal/cfgutil" 27 "decred.org/dcrwallet/v3/internal/loader" 28 "decred.org/dcrwallet/v3/internal/loggers" 29 "decred.org/dcrwallet/v3/internal/rpc/jsonrpc" 30 "decred.org/dcrwallet/v3/internal/rpc/rpcserver" 31 32 "google.golang.org/grpc" 33 "google.golang.org/grpc/codes" 34 "google.golang.org/grpc/credentials" 35 "google.golang.org/grpc/peer" 36 "google.golang.org/grpc/status" 37 ) 38 39 // openRPCKeyPair creates or loads the RPC TLS keypair specified by the 40 // application config. This function respects the cfg.OneTimeTLSKey setting. 41 func openRPCKeyPair() (tls.Certificate, error) { 42 // Check for existence of the TLS key file. If one time TLS keys are 43 // enabled but a key already exists, this function should error since 44 // it's possible that a persistent certificate was copied to a remote 45 // machine. Otherwise, generate a new keypair when the key is missing. 46 // When generating new persistent keys, overwriting an existing cert is 47 // acceptable if the previous execution used a one time TLS key. 48 // Otherwise, both the cert and key should be read from disk. If the 49 // cert is missing, the read error will occur in LoadX509KeyPair. 50 _, e := os.Stat(cfg.RPCKey.Value) 51 keyExists := !os.IsNotExist(e) 52 switch { 53 case cfg.OneTimeTLSKey && keyExists: 54 err := errors.Errorf("one time TLS keys are enabled, but TLS key "+ 55 "`%s` already exists", cfg.RPCKey) 56 return tls.Certificate{}, err 57 case cfg.OneTimeTLSKey: 58 return generateRPCKeyPair(false) 59 case !keyExists: 60 return generateRPCKeyPair(true) 61 default: 62 return tls.LoadX509KeyPair(cfg.RPCCert.Value, cfg.RPCKey.Value) 63 } 64 } 65 66 // generateRPCKeyPair generates a new RPC TLS keypair and writes the cert and 67 // possibly also the key in PEM format to the paths specified by the config. If 68 // successful, the new keypair is returned. 69 func generateRPCKeyPair(writeKey bool) (tls.Certificate, error) { 70 log.Infof("Generating TLS certificates...") 71 72 // Create directories for cert and key files if they do not yet exist. 73 certDir, _ := filepath.Split(cfg.RPCCert.Value) 74 keyDir, _ := filepath.Split(cfg.RPCKey.Value) 75 err := os.MkdirAll(certDir, 0700) 76 if err != nil { 77 return tls.Certificate{}, err 78 } 79 err = os.MkdirAll(keyDir, 0700) 80 if err != nil { 81 return tls.Certificate{}, err 82 } 83 84 // Generate cert pair. 85 org := "dcrwallet autogenerated cert" 86 validUntil := time.Now().Add(time.Hour * 24 * 365 * 10) 87 cert, key, err := cfg.TLSCurve.CertGen(org, validUntil, nil) 88 if err != nil { 89 return tls.Certificate{}, err 90 } 91 keyPair, err := tls.X509KeyPair(cert, key) 92 if err != nil { 93 return tls.Certificate{}, err 94 } 95 96 // Write cert and (potentially) the key files. 97 err = os.WriteFile(cfg.RPCCert.Value, cert, 0600) 98 if err != nil { 99 return tls.Certificate{}, err 100 } 101 if writeKey { 102 err = os.WriteFile(cfg.RPCKey.Value, key, 0600) 103 if err != nil { 104 rmErr := os.Remove(cfg.RPCCert.Value) 105 if rmErr != nil { 106 log.Warnf("Cannot remove written certificates: %v", 107 rmErr) 108 } 109 return tls.Certificate{}, err 110 } 111 } 112 113 log.Info("Done generating TLS certificates") 114 return keyPair, nil 115 } 116 117 func randomX509SerialNumber() (*big.Int, error) { 118 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 119 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 120 if err != nil { 121 return nil, fmt.Errorf("failed to generate serial number: %s", err) 122 } 123 return serialNumber, nil 124 } 125 126 // End of ASN.1 time 127 var endOfTime = time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) 128 129 type ClientCA struct { 130 CertBlock []byte 131 Cert *x509.Certificate 132 PrivateKey interface{} 133 } 134 135 func generateAuthority(pub, priv interface{}) (*ClientCA, error) { 136 validUntil := time.Now().Add(time.Hour * 24 * 365 * 10) 137 now := time.Now() 138 if validUntil.After(endOfTime) { 139 validUntil = endOfTime 140 } 141 if validUntil.Before(now) { 142 return nil, fmt.Errorf("valid until date %v already elapsed", validUntil) 143 } 144 serialNumber, err := randomX509SerialNumber() 145 if err != nil { 146 return nil, err 147 } 148 template := &x509.Certificate{ 149 SerialNumber: serialNumber, 150 Subject: pkix.Name{ 151 CommonName: "dcrwallet", 152 Organization: []string{"dcrwallet"}, 153 OrganizationalUnit: []string{"dcrwallet certificate authority"}, 154 }, 155 NotBefore: now.Add(-time.Hour * 24), 156 NotAfter: validUntil, 157 KeyUsage: x509.KeyUsageCertSign, 158 BasicConstraintsValid: true, 159 IsCA: true, 160 } 161 cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv) 162 if err != nil { 163 return nil, err 164 } 165 buf := new(bytes.Buffer) 166 err = pem.Encode(buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) 167 if err != nil { 168 return nil, fmt.Errorf("failed to encode certificate: %v", err) 169 } 170 certBlock := buf.Bytes() 171 172 x509Cert, err := x509.ParseCertificate(cert) 173 if err != nil { 174 return nil, err 175 } 176 177 clientCA := &ClientCA{ 178 CertBlock: certBlock, 179 Cert: x509Cert, 180 PrivateKey: priv, 181 } 182 return clientCA, nil 183 } 184 185 func marshalPrivateKey(key interface{}) ([]byte, error) { 186 der, err := x509.MarshalPKCS8PrivateKey(key) 187 if err != nil { 188 return nil, fmt.Errorf("failed to marshal private key: %v", err) 189 } 190 buf := new(bytes.Buffer) 191 err = pem.Encode(buf, &pem.Block{Type: "PRIVATE KEY", Bytes: der}) 192 if err != nil { 193 return nil, fmt.Errorf("failed to encode private key: %v", err) 194 } 195 return buf.Bytes(), nil 196 } 197 198 func createSignedClientCert(pub, caPriv interface{}, ca *x509.Certificate) ([]byte, error) { 199 serialNumber, err := randomX509SerialNumber() 200 if err != nil { 201 return nil, err 202 } 203 template := &x509.Certificate{ 204 SerialNumber: serialNumber, 205 NotBefore: time.Now().Add(-time.Hour * 24), 206 NotAfter: ca.NotAfter, 207 Subject: pkix.Name{ 208 CommonName: "dcrwallet", 209 Organization: []string{"dcrwallet"}, 210 OrganizationalUnit: []string{"dcrwallet client certificate"}, 211 }, 212 } 213 cert, err := x509.CreateCertificate(rand.Reader, template, ca, pub, caPriv) 214 if err != nil { 215 return nil, err 216 } 217 buf := new(bytes.Buffer) 218 err = pem.Encode(buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) 219 if err != nil { 220 return nil, fmt.Errorf("failed to encode certificate: %v", err) 221 } 222 return buf.Bytes(), nil 223 } 224 225 func generateClientKeyPair(caPriv interface{}, ca *x509.Certificate) (cert, key []byte, err error) { 226 pub, priv, err := cfg.TLSCurve.GenerateKeyPair(rand.Reader) 227 if err != nil { 228 return 229 } 230 key, err = marshalPrivateKey(priv) 231 if err != nil { 232 return 233 } 234 cert, err = createSignedClientCert(pub, caPriv, ca) 235 if err != nil { 236 return 237 } 238 return cert, key, nil 239 } 240 241 func startRPCServers(walletLoader *loader.Loader) (*grpc.Server, *jsonrpc.Server, error) { 242 var jsonrpcAddrNotifier jsonrpcListenerEventServer 243 var grpcAddrNotifier grpcListenerEventServer 244 if cfg.RPCListenerEvents { 245 jsonrpcAddrNotifier = newJSONRPCListenerEventServer(outgoingPipeMessages) 246 grpcAddrNotifier = newGRPCListenerEventServer(outgoingPipeMessages) 247 } 248 249 var ( 250 server *grpc.Server 251 jsonrpcServer *jsonrpc.Server 252 jsonrpcListen = net.Listen 253 keyPair tls.Certificate 254 clientCAsExist bool 255 err error 256 ) 257 if cfg.DisableServerTLS { 258 log.Info("Server TLS is disabled. Only JSON-RPC may be used") 259 } else { 260 keyPair, err = openRPCKeyPair() 261 if err != nil { 262 return nil, nil, err 263 } 264 265 tlsConfig := &tls.Config{ 266 Certificates: []tls.Certificate{keyPair}, 267 MinVersion: tls.VersionTLS12, 268 ClientCAs: x509.NewCertPool(), 269 } 270 clientCAsExist, _ = cfgutil.FileExists(cfg.ClientCAFile.Value) 271 if clientCAsExist { 272 cafile, err := os.ReadFile(cfg.ClientCAFile.Value) 273 if err != nil { 274 return nil, nil, err 275 } 276 if !tlsConfig.ClientCAs.AppendCertsFromPEM(cafile) { 277 log.Warnf("No certificates added from CA file %v", 278 cfg.ClientCAFile) 279 } 280 } 281 if cfg.JSONRPCAuthType == "clientcert" { 282 tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert 283 } 284 if cfg.IssueClientCert { 285 pub, priv, err := cfg.TLSCurve.GenerateKeyPair(rand.Reader) 286 if err != nil { 287 return nil, nil, err 288 } 289 ca, err := generateAuthority(pub, priv) 290 if err != nil { 291 return nil, nil, err 292 } 293 certBlock, keyBlock, err := generateClientKeyPair(ca.PrivateKey, ca.Cert) 294 if err != nil { 295 return nil, nil, err 296 } 297 tlsConfig.ClientCAs.AddCert(ca.Cert) 298 299 s := newIssuedClientCertEventServer(outgoingPipeMessages) 300 s.notify(keyBlock, certBlock, ca.CertBlock) 301 } 302 303 // Change the standard net.Listen function to the tls one. 304 jsonrpcListen = func(net string, laddr string) (net.Listener, error) { 305 return tls.Listen(net, laddr, tlsConfig) 306 } 307 308 clientCAsExist = clientCAsExist || cfg.IssueClientCert 309 if !clientCAsExist && len(cfg.GRPCListeners) != 0 { 310 log.Warnf("gRPC server is configured with listeners, but no "+ 311 "trusted client certificates exist (looked in %v)", 312 cfg.ClientCAFile) 313 } else if clientCAsExist && len(cfg.GRPCListeners) != 0 { 314 tlsConfig := tlsConfig.Clone() 315 tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert 316 listeners := makeListeners(cfg.GRPCListeners, net.Listen) 317 if len(listeners) == 0 { 318 err := errors.New("failed to create listeners for RPC server") 319 return nil, nil, err 320 } 321 server = grpc.NewServer( 322 grpc.Creds(credentials.NewTLS(tlsConfig)), 323 grpc.StreamInterceptor(interceptStreaming), 324 grpc.UnaryInterceptor(interceptUnary), 325 ) 326 rpcserver.RegisterServices(server) 327 rpcserver.StartWalletLoaderService(server, walletLoader, activeNet) 328 rpcserver.StartTicketBuyerV2Service(server, walletLoader) 329 rpcserver.StartAccountMixerService(server, walletLoader) 330 rpcserver.StartAgendaService(server, activeNet.Params) 331 rpcserver.StartDecodeMessageService(server, activeNet.Params) 332 rpcserver.StartMessageVerificationService(server, activeNet.Params) 333 for _, lis := range listeners { 334 lis := lis 335 go func() { 336 laddr := lis.Addr().String() 337 grpcAddrNotifier.notify(laddr) 338 log.Infof("gRPC server listening on %s", laddr) 339 err := server.Serve(lis) 340 log.Tracef("Finished serving gRPC: %v", err) 341 }() 342 } 343 } 344 } 345 346 if !cfg.DisableServerTLS && len(cfg.LegacyRPCListeners) != 0 && 347 cfg.JSONRPCAuthType == "clientcert" && !clientCAsExist { 348 log.Warnf("JSON-RPC TLS server is configured with listeners and "+ 349 "client cert auth, but no trusted client certificates exist "+ 350 "(looked in %v)", cfg.ClientCAFile) 351 } else if cfg.JSONRPCAuthType == "basic" && (cfg.Username == "" || cfg.Password == "") { 352 log.Info("JSON-RPC server disabled (basic auth requires username and " + 353 "password, and client cert authentication is not enabled)") 354 } else if len(cfg.LegacyRPCListeners) != 0 { 355 listeners := makeListeners(cfg.LegacyRPCListeners, jsonrpcListen) 356 if len(listeners) == 0 { 357 err := errors.New("failed to create listeners for JSON-RPC server") 358 return nil, nil, err 359 } 360 var user, pass string 361 if cfg.JSONRPCAuthType == "basic" { 362 user, pass = cfg.Username, cfg.Password 363 } 364 opts := jsonrpc.Options{ 365 Username: user, 366 Password: pass, 367 MaxPOSTClients: cfg.LegacyRPCMaxClients, 368 MaxWebsocketClients: cfg.LegacyRPCMaxWebsockets, 369 CSPPServer: cfg.CSPPServer, 370 DialCSPPServer: cfg.dialCSPPServer, 371 MixAccount: cfg.mixedAccount, 372 MixBranch: cfg.mixedBranch, 373 MixChangeAccount: cfg.ChangeAccount, 374 VSPHost: cfg.VSPOpts.URL, 375 VSPPubKey: cfg.VSPOpts.PubKey, 376 VSPMaxFee: cfg.VSPOpts.MaxFee.Amount, 377 TicketSplitAccount: cfg.TicketSplitAccount, 378 Dial: cfg.dial, 379 } 380 jsonrpcServer = jsonrpc.NewServer(&opts, activeNet.Params, walletLoader, listeners) 381 for _, lis := range listeners { 382 jsonrpcAddrNotifier.notify(lis.Addr().String()) 383 } 384 } 385 386 // Error when neither the GRPC nor JSON-RPC servers can be started. 387 if server == nil && jsonrpcServer == nil { 388 return nil, nil, errors.New("no suitable RPC services can be started") 389 } 390 391 return server, jsonrpcServer, nil 392 } 393 394 // serviceName returns the package.service segment from the full gRPC method 395 // name `/package.service/method`. 396 func serviceName(method string) string { 397 // Slice off first / 398 method = method[1:] 399 // Keep everything before the next / 400 return method[:strings.IndexRune(method, '/')] 401 } 402 403 func interceptStreaming(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 404 p, ok := peer.FromContext(ss.Context()) 405 if ok { 406 loggers.GrpcLog.Debugf("Streaming method %s invoked by %s", info.FullMethod, 407 p.Addr.String()) 408 } 409 err := rpcserver.ServiceReady(serviceName(info.FullMethod)) 410 if err != nil { 411 return err 412 } 413 err = handler(srv, ss) 414 if err != nil && ok { 415 logf := loggers.GrpcLog.Errorf 416 if status.Code(err) == codes.Canceled && done(ss.Context()) { 417 // Canceled contexts in streaming calls are expected 418 // when client-initiated, so only log them with debug 419 // level to reduce clutter. 420 logf = loggers.GrpcLog.Debugf 421 } 422 423 logf("Streaming method %s invoked by %s errored: %v", 424 info.FullMethod, p.Addr.String(), err) 425 } 426 return err 427 } 428 429 func interceptUnary(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { 430 p, ok := peer.FromContext(ctx) 431 if ok { 432 loggers.GrpcLog.Debugf("Unary method %s invoked by %s", info.FullMethod, 433 p.Addr.String()) 434 } 435 err = rpcserver.ServiceReady(serviceName(info.FullMethod)) 436 if err != nil { 437 return nil, err 438 } 439 resp, err = handler(ctx, req) 440 if err != nil && ok { 441 loggers.GrpcLog.Errorf("Unary method %s invoked by %s errored: %v", 442 info.FullMethod, p.Addr.String(), err) 443 } 444 return resp, err 445 } 446 447 type listenFunc func(net string, laddr string) (net.Listener, error) 448 449 // makeListeners splits the normalized listen addresses into IPv4 and IPv6 450 // addresses and creates new net.Listeners for each with the passed listen func. 451 // Invalid addresses are logged and skipped. 452 func makeListeners(normalizedListenAddrs []string, listen listenFunc) []net.Listener { 453 ipv4Addrs := make([]string, 0, len(normalizedListenAddrs)*2) 454 ipv6Addrs := make([]string, 0, len(normalizedListenAddrs)*2) 455 for _, addr := range normalizedListenAddrs { 456 host, _, err := net.SplitHostPort(addr) 457 if err != nil { 458 // Shouldn't happen due to already being normalized. 459 log.Errorf("`%s` is not a normalized "+ 460 "listener address", addr) 461 continue 462 } 463 464 // Empty host or host of * on plan9 is both IPv4 and IPv6. 465 if host == "" || (host == "*" && runtime.GOOS == "plan9") { 466 ipv4Addrs = append(ipv4Addrs, addr) 467 ipv6Addrs = append(ipv6Addrs, addr) 468 continue 469 } 470 471 // Remove the IPv6 zone from the host, if present. The zone 472 // prevents ParseIP from correctly parsing the IP address. 473 // ResolveIPAddr is intentionally not used here due to the 474 // possibility of leaking a DNS query over Tor if the host is a 475 // hostname and not an IP address. 476 zoneIndex := strings.Index(host, "%") 477 if zoneIndex != -1 { 478 host = host[:zoneIndex] 479 } 480 481 ip := net.ParseIP(host) 482 switch { 483 case ip == nil: 484 log.Warnf("`%s` is not a valid IP address", host) 485 case ip.To4() == nil: 486 ipv6Addrs = append(ipv6Addrs, addr) 487 default: 488 ipv4Addrs = append(ipv4Addrs, addr) 489 } 490 } 491 listeners := make([]net.Listener, 0, len(ipv6Addrs)+len(ipv4Addrs)) 492 for _, addr := range ipv4Addrs { 493 listener, err := listen("tcp4", addr) 494 if err != nil { 495 log.Warnf("Can't listen on %s: %v", addr, err) 496 continue 497 } 498 listeners = append(listeners, listener) 499 } 500 for _, addr := range ipv6Addrs { 501 listener, err := listen("tcp6", addr) 502 if err != nil { 503 log.Warnf("Can't listen on %s: %v", addr, err) 504 continue 505 } 506 listeners = append(listeners, listener) 507 } 508 return listeners 509 }