github.com/outbrain/consul@v1.4.5/agent/connect/ca/provider_consul.go (about)

     1  package ca
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/pem"
    10  	"errors"
    11  	"fmt"
    12  	"math/big"
    13  	"net/url"
    14  	"strings"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/hashicorp/consul/agent/connect"
    19  	"github.com/hashicorp/consul/agent/consul/state"
    20  	"github.com/hashicorp/consul/agent/structs"
    21  )
    22  
    23  var ErrNotInitialized = errors.New("provider not initialized")
    24  
    25  type ConsulProvider struct {
    26  	Delegate ConsulProviderStateDelegate
    27  
    28  	config    *structs.ConsulCAProviderConfig
    29  	id        string
    30  	clusterID string
    31  	isRoot    bool
    32  	spiffeID  *connect.SpiffeIDSigning
    33  
    34  	sync.RWMutex
    35  }
    36  
    37  type ConsulProviderStateDelegate interface {
    38  	State() *state.Store
    39  	ApplyCARequest(*structs.CARequest) error
    40  }
    41  
    42  // Configure sets up the provider using the given configuration.
    43  func (c *ConsulProvider) Configure(clusterID string, isRoot bool, rawConfig map[string]interface{}) error {
    44  	// Parse the raw config and update our ID.
    45  	config, err := ParseConsulCAConfig(rawConfig)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	c.config = config
    50  	hash := sha256.Sum256([]byte(fmt.Sprintf("%s,%s,%v", config.PrivateKey, config.RootCert, isRoot)))
    51  	c.id = strings.Replace(fmt.Sprintf("% x", hash), " ", ":", -1)
    52  	c.clusterID = clusterID
    53  	c.isRoot = isRoot
    54  	c.spiffeID = connect.SpiffeIDSigningForCluster(&structs.CAConfiguration{ClusterID: clusterID})
    55  
    56  	// Exit early if the state store has an entry for this provider's config.
    57  	_, providerState, err := c.Delegate.State().CAProviderState(c.id)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	if providerState != nil {
    63  		return nil
    64  	}
    65  
    66  	// Check if there's an entry with the old ID scheme.
    67  	oldID := fmt.Sprintf("%s,%s", config.PrivateKey, config.RootCert)
    68  	_, providerState, err = c.Delegate.State().CAProviderState(oldID)
    69  	if err != nil {
    70  		return err
    71  	}
    72  
    73  	// Found an entry with the old ID, so update it to the new ID and
    74  	// delete the old entry.
    75  	if providerState != nil {
    76  		newState := *providerState
    77  		newState.ID = c.id
    78  		createReq := &structs.CARequest{
    79  			Op:            structs.CAOpSetProviderState,
    80  			ProviderState: &newState,
    81  		}
    82  		if err := c.Delegate.ApplyCARequest(createReq); err != nil {
    83  			return err
    84  		}
    85  
    86  		deleteReq := &structs.CARequest{
    87  			Op:            structs.CAOpDeleteProviderState,
    88  			ProviderState: providerState,
    89  		}
    90  		if err := c.Delegate.ApplyCARequest(deleteReq); err != nil {
    91  			return err
    92  		}
    93  
    94  		return nil
    95  	}
    96  
    97  	// Write the provider state to the state store.
    98  	newState := structs.CAConsulProviderState{
    99  		ID: c.id,
   100  	}
   101  
   102  	args := &structs.CARequest{
   103  		Op:            structs.CAOpSetProviderState,
   104  		ProviderState: &newState,
   105  	}
   106  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   107  		return err
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  // ActiveRoot returns the active root CA certificate.
   114  func (c *ConsulProvider) ActiveRoot() (string, error) {
   115  	_, providerState, err := c.getState()
   116  	if err != nil {
   117  		return "", err
   118  	}
   119  
   120  	return providerState.RootCert, nil
   121  }
   122  
   123  // GenerateRoot initializes a new root certificate and private key
   124  // if needed.
   125  func (c *ConsulProvider) GenerateRoot() error {
   126  	idx, providerState, err := c.getState()
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	if !c.isRoot {
   132  		return fmt.Errorf("provider is not the root certificate authority")
   133  	}
   134  	if providerState.RootCert != "" {
   135  		return nil
   136  	}
   137  
   138  	// Generate a private key if needed
   139  	newState := *providerState
   140  	if c.config.PrivateKey == "" {
   141  		_, pk, err := connect.GeneratePrivateKey()
   142  		if err != nil {
   143  			return err
   144  		}
   145  		newState.PrivateKey = pk
   146  	} else {
   147  		newState.PrivateKey = c.config.PrivateKey
   148  	}
   149  
   150  	// Generate the root CA if necessary
   151  	if c.config.RootCert == "" {
   152  		ca, err := c.generateCA(newState.PrivateKey, idx+1)
   153  		if err != nil {
   154  			return fmt.Errorf("error generating CA: %v", err)
   155  		}
   156  		newState.RootCert = ca
   157  	} else {
   158  		newState.RootCert = c.config.RootCert
   159  	}
   160  
   161  	// Write the provider state
   162  	args := &structs.CARequest{
   163  		Op:            structs.CAOpSetProviderState,
   164  		ProviderState: &newState,
   165  	}
   166  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   167  		return err
   168  	}
   169  
   170  	return nil
   171  }
   172  
   173  // GenerateIntermediateCSR creates a private key and generates a CSR
   174  // for another datacenter's root to sign.
   175  func (c *ConsulProvider) GenerateIntermediateCSR() (string, error) {
   176  	_, providerState, err := c.getState()
   177  	if err != nil {
   178  		return "", err
   179  	}
   180  
   181  	if c.isRoot {
   182  		return "", fmt.Errorf("provider is the root certificate authority, " +
   183  			"cannot generate an intermediate CSR")
   184  	}
   185  
   186  	// Create a new private key and CSR.
   187  	signer, pk, err := connect.GeneratePrivateKey()
   188  	if err != nil {
   189  		return "", err
   190  	}
   191  
   192  	csr, err := connect.CreateCACSR(c.spiffeID, signer)
   193  	if err != nil {
   194  		return "", err
   195  	}
   196  
   197  	// Write the new provider state to the store.
   198  	newState := *providerState
   199  	newState.PrivateKey = pk
   200  	args := &structs.CARequest{
   201  		Op:            structs.CAOpSetProviderState,
   202  		ProviderState: &newState,
   203  	}
   204  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   205  		return "", err
   206  	}
   207  
   208  	return csr, nil
   209  }
   210  
   211  // SetIntermediate validates that the given intermediate is for the right private key
   212  // and writes the given intermediate and root certificates to the state.
   213  func (c *ConsulProvider) SetIntermediate(intermediatePEM, rootPEM string) error {
   214  	_, providerState, err := c.getState()
   215  	if err != nil {
   216  		return err
   217  	}
   218  
   219  	if c.isRoot {
   220  		return fmt.Errorf("cannot set an intermediate using another root in the primary datacenter")
   221  	}
   222  
   223  	// Get the key from the incoming intermediate cert so we can compare it
   224  	// to the currently stored key.
   225  	intermediate, err := connect.ParseCert(intermediatePEM)
   226  	if err != nil {
   227  		return fmt.Errorf("error parsing intermediate PEM: %v", err)
   228  	}
   229  	privKey, err := connect.ParseSigner(providerState.PrivateKey)
   230  	if err != nil {
   231  		return err
   232  	}
   233  
   234  	// Compare the two keys to make sure they match.
   235  	b1, err := x509.MarshalPKIXPublicKey(intermediate.PublicKey)
   236  	if err != nil {
   237  		return err
   238  	}
   239  	b2, err := x509.MarshalPKIXPublicKey(privKey.Public())
   240  	if err != nil {
   241  		return err
   242  	}
   243  	if !bytes.Equal(b1, b2) {
   244  		return fmt.Errorf("intermediate cert is for a different private key")
   245  	}
   246  
   247  	// Validate the remaining fields and make sure the intermediate validates against
   248  	// the given root cert.
   249  	if !intermediate.IsCA {
   250  		return fmt.Errorf("intermediate is not a CA certificate")
   251  	}
   252  	if uriCount := len(intermediate.URIs); uriCount != 1 {
   253  		return fmt.Errorf("incoming intermediate cert has unexpected number of URIs: %d", uriCount)
   254  	}
   255  	if got, want := intermediate.URIs[0].String(), c.spiffeID.URI().String(); got != want {
   256  		return fmt.Errorf("incoming cert URI %q does not match current URI: %q", got, want)
   257  	}
   258  
   259  	pool := x509.NewCertPool()
   260  	pool.AppendCertsFromPEM([]byte(rootPEM))
   261  	_, err = intermediate.Verify(x509.VerifyOptions{
   262  		Roots: pool,
   263  	})
   264  	if err != nil {
   265  		return fmt.Errorf("could not verify intermediate cert against root: %v", err)
   266  	}
   267  
   268  	// Update the state
   269  	newState := *providerState
   270  	newState.IntermediateCert = intermediatePEM
   271  	newState.RootCert = rootPEM
   272  	args := &structs.CARequest{
   273  		Op:            structs.CAOpSetProviderState,
   274  		ProviderState: &newState,
   275  	}
   276  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   277  		return err
   278  	}
   279  
   280  	return nil
   281  }
   282  
   283  // We aren't maintaining separate root/intermediate CAs for the builtin
   284  // provider, so just return the root.
   285  func (c *ConsulProvider) ActiveIntermediate() (string, error) {
   286  	if c.isRoot {
   287  		return c.ActiveRoot()
   288  	}
   289  
   290  	_, providerState, err := c.getState()
   291  	if err != nil {
   292  		return "", err
   293  	}
   294  
   295  	return providerState.IntermediateCert, nil
   296  }
   297  
   298  // We aren't maintaining separate root/intermediate CAs for the builtin
   299  // provider, so just return the root.
   300  func (c *ConsulProvider) GenerateIntermediate() (string, error) {
   301  	return c.ActiveIntermediate()
   302  }
   303  
   304  // Remove the state store entry for this provider instance.
   305  func (c *ConsulProvider) Cleanup() error {
   306  	args := &structs.CARequest{
   307  		Op:            structs.CAOpDeleteProviderState,
   308  		ProviderState: &structs.CAConsulProviderState{ID: c.id},
   309  	}
   310  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   311  		return err
   312  	}
   313  
   314  	return nil
   315  }
   316  
   317  // Sign returns a new certificate valid for the given SpiffeIDService
   318  // using the current CA.
   319  func (c *ConsulProvider) Sign(csr *x509.CertificateRequest) (string, error) {
   320  	// Lock during the signing so we don't use the same index twice
   321  	// for different cert serial numbers.
   322  	c.Lock()
   323  	defer c.Unlock()
   324  
   325  	// Get the provider state
   326  	idx, providerState, err := c.getState()
   327  	if err != nil {
   328  		return "", err
   329  	}
   330  	if providerState.PrivateKey == "" {
   331  		return "", ErrNotInitialized
   332  	}
   333  
   334  	// Create the keyId for the cert from the signing private key.
   335  	signer, err := connect.ParseSigner(providerState.PrivateKey)
   336  	if err != nil {
   337  		return "", err
   338  	}
   339  	if signer == nil {
   340  		return "", ErrNotInitialized
   341  	}
   342  	keyId, err := connect.KeyId(signer.Public())
   343  	if err != nil {
   344  		return "", err
   345  	}
   346  
   347  	// Parse the SPIFFE ID
   348  	spiffeId, err := connect.ParseCertURI(csr.URIs[0])
   349  	if err != nil {
   350  		return "", err
   351  	}
   352  	serviceId, ok := spiffeId.(*connect.SpiffeIDService)
   353  	if !ok {
   354  		return "", fmt.Errorf("SPIFFE ID in CSR must be a service ID")
   355  	}
   356  
   357  	// Parse the CA cert
   358  	certPEM, err := c.ActiveIntermediate()
   359  	if err != nil {
   360  		return "", err
   361  	}
   362  	caCert, err := connect.ParseCert(certPEM)
   363  	if err != nil {
   364  		return "", fmt.Errorf("error parsing CA cert: %s", err)
   365  	}
   366  
   367  	// Cert template for generation
   368  	sn := &big.Int{}
   369  	sn.SetUint64(idx + 1)
   370  	// Sign the certificate valid from 1 minute in the past, this helps it be
   371  	// accepted right away even when nodes are not in close time sync across the
   372  	// cluster. A minute is more than enough for typical DC clock drift.
   373  	effectiveNow := time.Now().Add(-1 * time.Minute)
   374  	template := x509.Certificate{
   375  		SerialNumber:          sn,
   376  		Subject:               pkix.Name{CommonName: serviceId.Service},
   377  		URIs:                  csr.URIs,
   378  		Signature:             csr.Signature,
   379  		SignatureAlgorithm:    csr.SignatureAlgorithm,
   380  		PublicKeyAlgorithm:    csr.PublicKeyAlgorithm,
   381  		PublicKey:             csr.PublicKey,
   382  		BasicConstraintsValid: true,
   383  		KeyUsage: x509.KeyUsageDataEncipherment |
   384  			x509.KeyUsageKeyAgreement |
   385  			x509.KeyUsageDigitalSignature |
   386  			x509.KeyUsageKeyEncipherment,
   387  		ExtKeyUsage: []x509.ExtKeyUsage{
   388  			x509.ExtKeyUsageClientAuth,
   389  			x509.ExtKeyUsageServerAuth,
   390  		},
   391  		NotAfter:       effectiveNow.Add(c.config.LeafCertTTL),
   392  		NotBefore:      effectiveNow,
   393  		AuthorityKeyId: keyId,
   394  		SubjectKeyId:   keyId,
   395  	}
   396  
   397  	// Create the certificate, PEM encode it and return that value.
   398  	var buf bytes.Buffer
   399  	bs, err := x509.CreateCertificate(
   400  		rand.Reader, &template, caCert, csr.PublicKey, signer)
   401  	if err != nil {
   402  		return "", fmt.Errorf("error generating certificate: %s", err)
   403  	}
   404  	err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs})
   405  	if err != nil {
   406  		return "", fmt.Errorf("error encoding certificate: %s", err)
   407  	}
   408  
   409  	err = c.incrementProviderIndex(providerState)
   410  	if err != nil {
   411  		return "", err
   412  	}
   413  
   414  	// Set the response
   415  	return buf.String(), nil
   416  }
   417  
   418  // SignIntermediate will validate the CSR to ensure the trust domain in the
   419  // URI SAN matches the local one and that basic constraints for a CA certificate
   420  // are met. It should return a signed CA certificate with a path length constraint
   421  // of 0 to ensure that the certificate cannot be used to generate further CA certs.
   422  func (c *ConsulProvider) SignIntermediate(csr *x509.CertificateRequest) (string, error) {
   423  	idx, providerState, err := c.getState()
   424  	if err != nil {
   425  		return "", err
   426  	}
   427  
   428  	if uriCount := len(csr.URIs); uriCount != 1 {
   429  		return "", fmt.Errorf("incoming CSR has unexpected number of URIs: %d", uriCount)
   430  	}
   431  	certURI, err := connect.ParseCertURI(csr.URIs[0])
   432  	if err != nil {
   433  		return "", err
   434  	}
   435  
   436  	// Verify that the trust domain is valid.
   437  	if !c.spiffeID.CanSign(certURI) {
   438  		return "", fmt.Errorf("incoming CSR domain %q is not valid for our domain %q",
   439  			certURI.URI().String(), c.spiffeID.URI().String())
   440  	}
   441  
   442  	// Get the signing private key.
   443  	signer, err := connect.ParseSigner(providerState.PrivateKey)
   444  	if err != nil {
   445  		return "", err
   446  	}
   447  	subjectKeyId, err := connect.KeyId(csr.PublicKey)
   448  	if err != nil {
   449  		return "", err
   450  	}
   451  
   452  	// Parse the CA cert
   453  	caCert, err := connect.ParseCert(providerState.RootCert)
   454  	if err != nil {
   455  		return "", fmt.Errorf("error parsing CA cert: %s", err)
   456  	}
   457  
   458  	// Cert template for generation
   459  	sn := &big.Int{}
   460  	sn.SetUint64(idx + 1)
   461  	// Sign the certificate valid from 1 minute in the past, this helps it be
   462  	// accepted right away even when nodes are not in close time sync across the
   463  	// cluster. A minute is more than enough for typical DC clock drift.
   464  	effectiveNow := time.Now().Add(-1 * time.Minute)
   465  	template := x509.Certificate{
   466  		SerialNumber:          sn,
   467  		Subject:               csr.Subject,
   468  		URIs:                  csr.URIs,
   469  		Signature:             csr.Signature,
   470  		SignatureAlgorithm:    csr.SignatureAlgorithm,
   471  		PublicKeyAlgorithm:    csr.PublicKeyAlgorithm,
   472  		PublicKey:             csr.PublicKey,
   473  		BasicConstraintsValid: true,
   474  		KeyUsage: x509.KeyUsageCertSign |
   475  			x509.KeyUsageCRLSign |
   476  			x509.KeyUsageDigitalSignature,
   477  		IsCA:           true,
   478  		MaxPathLenZero: true,
   479  		NotAfter:       effectiveNow.AddDate(1, 0, 0),
   480  		NotBefore:      effectiveNow,
   481  		SubjectKeyId:   subjectKeyId,
   482  	}
   483  
   484  	// Create the certificate, PEM encode it and return that value.
   485  	var buf bytes.Buffer
   486  	bs, err := x509.CreateCertificate(
   487  		rand.Reader, &template, caCert, csr.PublicKey, signer)
   488  	if err != nil {
   489  		return "", fmt.Errorf("error generating certificate: %s", err)
   490  	}
   491  	err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs})
   492  	if err != nil {
   493  		return "", fmt.Errorf("error encoding certificate: %s", err)
   494  	}
   495  
   496  	err = c.incrementProviderIndex(providerState)
   497  	if err != nil {
   498  		return "", err
   499  	}
   500  
   501  	// Set the response
   502  	return buf.String(), nil
   503  }
   504  
   505  // CrossSignCA returns the given CA cert signed by the current active root.
   506  func (c *ConsulProvider) CrossSignCA(cert *x509.Certificate) (string, error) {
   507  	c.Lock()
   508  	defer c.Unlock()
   509  
   510  	// Get the provider state
   511  	idx, providerState, err := c.getState()
   512  	if err != nil {
   513  		return "", err
   514  	}
   515  
   516  	privKey, err := connect.ParseSigner(providerState.PrivateKey)
   517  	if err != nil {
   518  		return "", fmt.Errorf("error parsing private key %q: %s", providerState.PrivateKey, err)
   519  	}
   520  
   521  	rootCA, err := connect.ParseCert(providerState.RootCert)
   522  	if err != nil {
   523  		return "", err
   524  	}
   525  
   526  	keyId, err := connect.KeyId(privKey.Public())
   527  	if err != nil {
   528  		return "", err
   529  	}
   530  
   531  	// Create the cross-signing template from the existing root CA
   532  	serialNum := &big.Int{}
   533  	serialNum.SetUint64(idx + 1)
   534  	template := *cert
   535  	template.SerialNumber = serialNum
   536  	template.SignatureAlgorithm = rootCA.SignatureAlgorithm
   537  	template.AuthorityKeyId = keyId
   538  
   539  	// Sign the certificate valid from 1 minute in the past, this helps it be
   540  	// accepted right away even when nodes are not in close time sync across the
   541  	// cluster. A minute is more than enough for typical DC clock drift.
   542  	effectiveNow := time.Now().Add(-1 * time.Minute)
   543  	template.NotBefore = effectiveNow
   544  	// This cross-signed cert is only needed during rotation, and only while old
   545  	// leaf certs are still in use. They expire within 3 days currently so 7 is
   546  	// safe. TODO(banks): make this be based on leaf expiry time when that is
   547  	// configurable.
   548  	template.NotAfter = effectiveNow.AddDate(0, 0, 7)
   549  
   550  	bs, err := x509.CreateCertificate(
   551  		rand.Reader, &template, rootCA, cert.PublicKey, privKey)
   552  	if err != nil {
   553  		return "", fmt.Errorf("error generating CA certificate: %s", err)
   554  	}
   555  
   556  	var buf bytes.Buffer
   557  	err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs})
   558  	if err != nil {
   559  		return "", fmt.Errorf("error encoding private key: %s", err)
   560  	}
   561  
   562  	err = c.incrementProviderIndex(providerState)
   563  	if err != nil {
   564  		return "", err
   565  	}
   566  
   567  	return buf.String(), nil
   568  }
   569  
   570  // getState returns the current provider state from the state delegate, and returns
   571  // ErrNotInitialized if no entry is found.
   572  func (c *ConsulProvider) getState() (uint64, *structs.CAConsulProviderState, error) {
   573  	state := c.Delegate.State()
   574  	idx, providerState, err := state.CAProviderState(c.id)
   575  	if err != nil {
   576  		return 0, nil, err
   577  	}
   578  
   579  	if providerState == nil {
   580  		return 0, nil, ErrNotInitialized
   581  	}
   582  
   583  	return idx, providerState, nil
   584  }
   585  
   586  // incrementProviderIndex does a write to increment the provider state store table index
   587  // used for serial numbers when generating certificates.
   588  func (c *ConsulProvider) incrementProviderIndex(providerState *structs.CAConsulProviderState) error {
   589  	newState := *providerState
   590  	args := &structs.CARequest{
   591  		Op:            structs.CAOpSetProviderState,
   592  		ProviderState: &newState,
   593  	}
   594  	if err := c.Delegate.ApplyCARequest(args); err != nil {
   595  		return err
   596  	}
   597  
   598  	return nil
   599  }
   600  
   601  // generateCA makes a new root CA using the current private key
   602  func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error) {
   603  	state := c.Delegate.State()
   604  	_, config, err := state.CAConfig()
   605  	if err != nil {
   606  		return "", err
   607  	}
   608  
   609  	privKey, err := connect.ParseSigner(privateKey)
   610  	if err != nil {
   611  		return "", fmt.Errorf("error parsing private key %q: %s", privateKey, err)
   612  	}
   613  
   614  	name := fmt.Sprintf("Consul CA %d", sn)
   615  
   616  	// The URI (SPIFFE compatible) for the cert
   617  	id := connect.SpiffeIDSigningForCluster(config)
   618  	keyId, err := connect.KeyId(privKey.Public())
   619  	if err != nil {
   620  		return "", err
   621  	}
   622  
   623  	// Create the CA cert
   624  	serialNum := &big.Int{}
   625  	serialNum.SetUint64(sn)
   626  	template := x509.Certificate{
   627  		SerialNumber:          serialNum,
   628  		Subject:               pkix.Name{CommonName: name},
   629  		URIs:                  []*url.URL{id.URI()},
   630  		BasicConstraintsValid: true,
   631  		KeyUsage: x509.KeyUsageCertSign |
   632  			x509.KeyUsageCRLSign |
   633  			x509.KeyUsageDigitalSignature,
   634  		IsCA:           true,
   635  		NotAfter:       time.Now().AddDate(10, 0, 0),
   636  		NotBefore:      time.Now(),
   637  		AuthorityKeyId: keyId,
   638  		SubjectKeyId:   keyId,
   639  	}
   640  
   641  	bs, err := x509.CreateCertificate(
   642  		rand.Reader, &template, &template, privKey.Public(), privKey)
   643  	if err != nil {
   644  		return "", fmt.Errorf("error generating CA certificate: %s", err)
   645  	}
   646  
   647  	var buf bytes.Buffer
   648  	err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs})
   649  	if err != nil {
   650  		return "", fmt.Errorf("error encoding private key: %s", err)
   651  	}
   652  
   653  	return buf.String(), nil
   654  }