github.com/gophercloud/gophercloud@v1.11.0/internal/acceptance/openstack/keymanager/v1/keymanager.go (about)

     1  package v1
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/rsa"
     6  	"crypto/x509"
     7  	"crypto/x509/pkix"
     8  	"encoding/asn1"
     9  	"encoding/base64"
    10  	"encoding/pem"
    11  	"fmt"
    12  	"math/big"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/gophercloud/gophercloud"
    18  	"github.com/gophercloud/gophercloud/internal/acceptance/tools"
    19  	"github.com/gophercloud/gophercloud/openstack/keymanager/v1/containers"
    20  	"github.com/gophercloud/gophercloud/openstack/keymanager/v1/orders"
    21  	"github.com/gophercloud/gophercloud/openstack/keymanager/v1/secrets"
    22  	th "github.com/gophercloud/gophercloud/testhelper"
    23  )
    24  
    25  // CreateAsymmetric Order will create a random asymmetric order.
    26  // An error will be returned if the order could not be created.
    27  func CreateAsymmetricOrder(t *testing.T, client *gophercloud.ServiceClient) (*orders.Order, error) {
    28  	name := tools.RandomString("TESTACC-", 8)
    29  	t.Logf("Attempting to create order %s", name)
    30  
    31  	expiration := time.Date(2049, 1, 1, 1, 1, 1, 0, time.UTC)
    32  	createOpts := orders.CreateOpts{
    33  		Type: orders.AsymmetricOrder,
    34  		Meta: orders.MetaOpts{
    35  			Name:       name,
    36  			Algorithm:  "rsa",
    37  			BitLength:  2048,
    38  			Mode:       "cbc",
    39  			Expiration: &expiration,
    40  		},
    41  	}
    42  
    43  	order, err := orders.Create(client, createOpts).Extract()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	orderID, err := ParseID(order.OrderRef)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	err = WaitForOrder(client, orderID)
    54  	th.AssertNoErr(t, err)
    55  
    56  	order, err = orders.Get(client, orderID).Extract()
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	tools.PrintResource(t, order)
    62  	tools.PrintResource(t, order.Meta.Expiration)
    63  
    64  	th.AssertEquals(t, order.Meta.Name, name)
    65  	th.AssertEquals(t, order.Type, "asymmetric")
    66  
    67  	return order, nil
    68  }
    69  
    70  // CreateCertificateContainer will create a random certificate container.
    71  // An error will be returned if the container could not be created.
    72  func CreateCertificateContainer(t *testing.T, client *gophercloud.ServiceClient, passphrase, private, certificate *secrets.Secret) (*containers.Container, error) {
    73  	containerName := tools.RandomString("TESTACC-", 8)
    74  
    75  	t.Logf("Attempting to create container %s", containerName)
    76  
    77  	createOpts := containers.CreateOpts{
    78  		Type: containers.CertificateContainer,
    79  		Name: containerName,
    80  		SecretRefs: []containers.SecretRef{
    81  			{
    82  				Name:      "certificate",
    83  				SecretRef: certificate.SecretRef,
    84  			},
    85  			{
    86  				Name:      "private_key",
    87  				SecretRef: private.SecretRef,
    88  			},
    89  			{
    90  				Name:      "private_key_passphrase",
    91  				SecretRef: passphrase.SecretRef,
    92  			},
    93  		},
    94  	}
    95  
    96  	container, err := containers.Create(client, createOpts).Extract()
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	t.Logf("Successfully created container: %s", container.ContainerRef)
   102  
   103  	containerID, err := ParseID(container.ContainerRef)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	container, err = containers.Get(client, containerID).Extract()
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	tools.PrintResource(t, container)
   114  
   115  	th.AssertEquals(t, container.Name, containerName)
   116  	th.AssertEquals(t, container.Type, "certificate")
   117  
   118  	return container, nil
   119  }
   120  
   121  // CreateKeyOrder will create a random key order.
   122  // An error will be returned if the order could not be created.
   123  func CreateKeyOrder(t *testing.T, client *gophercloud.ServiceClient) (*orders.Order, error) {
   124  	name := tools.RandomString("TESTACC-", 8)
   125  	t.Logf("Attempting to create order %s", name)
   126  
   127  	expiration := time.Date(2049, 1, 1, 1, 1, 1, 0, time.UTC)
   128  	createOpts := orders.CreateOpts{
   129  		Type: orders.KeyOrder,
   130  		Meta: orders.MetaOpts{
   131  			Name:       name,
   132  			Algorithm:  "aes",
   133  			BitLength:  256,
   134  			Mode:       "cbc",
   135  			Expiration: &expiration,
   136  		},
   137  	}
   138  
   139  	order, err := orders.Create(client, createOpts).Extract()
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	orderID, err := ParseID(order.OrderRef)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	order, err = orders.Get(client, orderID).Extract()
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	tools.PrintResource(t, order)
   155  	tools.PrintResource(t, order.Meta.Expiration)
   156  
   157  	th.AssertEquals(t, order.Meta.Name, name)
   158  	th.AssertEquals(t, order.Type, "key")
   159  
   160  	return order, nil
   161  }
   162  
   163  // CreateRSAContainer will create a random RSA container.
   164  // An error will be returned if the container could not be created.
   165  func CreateRSAContainer(t *testing.T, client *gophercloud.ServiceClient, passphrase, private, public *secrets.Secret) (*containers.Container, error) {
   166  	containerName := tools.RandomString("TESTACC-", 8)
   167  
   168  	t.Logf("Attempting to create container %s", containerName)
   169  
   170  	createOpts := containers.CreateOpts{
   171  		Type: containers.RSAContainer,
   172  		Name: containerName,
   173  		SecretRefs: []containers.SecretRef{
   174  			{
   175  				Name:      "public_key",
   176  				SecretRef: public.SecretRef,
   177  			},
   178  			{
   179  				Name:      "private_key",
   180  				SecretRef: private.SecretRef,
   181  			},
   182  			{
   183  				Name:      "private_key_passphrase",
   184  				SecretRef: passphrase.SecretRef,
   185  			},
   186  		},
   187  	}
   188  
   189  	container, err := containers.Create(client, createOpts).Extract()
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  
   194  	t.Logf("Successfully created container: %s", container.ContainerRef)
   195  
   196  	containerID, err := ParseID(container.ContainerRef)
   197  	if err != nil {
   198  		return nil, err
   199  	}
   200  
   201  	container, err = containers.Get(client, containerID).Extract()
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	tools.PrintResource(t, container)
   207  
   208  	th.AssertEquals(t, container.Name, containerName)
   209  	th.AssertEquals(t, container.Type, "rsa")
   210  
   211  	return container, nil
   212  }
   213  
   214  // CreateCertificateSecret will create a random certificate secret. An error
   215  // will be returned if the secret could not be created.
   216  func CreateCertificateSecret(t *testing.T, client *gophercloud.ServiceClient, cert []byte) (*secrets.Secret, error) {
   217  	b64Cert := base64.StdEncoding.EncodeToString(cert)
   218  
   219  	name := tools.RandomString("TESTACC-", 8)
   220  	t.Logf("Attempting to create public key %s", name)
   221  
   222  	createOpts := secrets.CreateOpts{
   223  		Name:                   name,
   224  		SecretType:             secrets.CertificateSecret,
   225  		Payload:                b64Cert,
   226  		PayloadContentType:     "application/octet-stream",
   227  		PayloadContentEncoding: "base64",
   228  		Algorithm:              "rsa",
   229  	}
   230  
   231  	secret, err := secrets.Create(client, createOpts).Extract()
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  
   236  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   237  
   238  	secretID, err := ParseID(secret.SecretRef)
   239  	if err != nil {
   240  		return nil, err
   241  	}
   242  
   243  	secret, err = secrets.Get(client, secretID).Extract()
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  
   248  	tools.PrintResource(t, secret)
   249  
   250  	th.AssertEquals(t, secret.Name, name)
   251  	th.AssertEquals(t, secret.Algorithm, "rsa")
   252  
   253  	return secret, nil
   254  }
   255  
   256  // CreateEmptySecret will create a random secret with no payload. An error will
   257  // be returned if the secret could not be created.
   258  func CreateEmptySecret(t *testing.T, client *gophercloud.ServiceClient) (*secrets.Secret, error) {
   259  	secretName := tools.RandomString("TESTACC-", 8)
   260  
   261  	t.Logf("Attempting to create secret %s", secretName)
   262  
   263  	createOpts := secrets.CreateOpts{
   264  		Algorithm:  "aes",
   265  		BitLength:  256,
   266  		Mode:       "cbc",
   267  		Name:       secretName,
   268  		SecretType: secrets.OpaqueSecret,
   269  	}
   270  
   271  	secret, err := secrets.Create(client, createOpts).Extract()
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  
   276  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   277  
   278  	secretID, err := ParseID(secret.SecretRef)
   279  	if err != nil {
   280  		return nil, err
   281  	}
   282  
   283  	secret, err = secrets.Get(client, secretID).Extract()
   284  	if err != nil {
   285  		return nil, err
   286  	}
   287  
   288  	tools.PrintResource(t, secret)
   289  
   290  	th.AssertEquals(t, secret.Name, secretName)
   291  	th.AssertEquals(t, secret.Algorithm, "aes")
   292  
   293  	return secret, nil
   294  }
   295  
   296  // CreateGenericContainer will create a random generic container with a
   297  // specified secret. An error will be returned if the container could not
   298  // be created.
   299  func CreateGenericContainer(t *testing.T, client *gophercloud.ServiceClient, secret *secrets.Secret) (*containers.Container, error) {
   300  	containerName := tools.RandomString("TESTACC-", 8)
   301  
   302  	t.Logf("Attempting to create container %s", containerName)
   303  
   304  	createOpts := containers.CreateOpts{
   305  		Type: containers.GenericContainer,
   306  		Name: containerName,
   307  		SecretRefs: []containers.SecretRef{
   308  			{
   309  				Name:      secret.Name,
   310  				SecretRef: secret.SecretRef,
   311  			},
   312  		},
   313  	}
   314  
   315  	container, err := containers.Create(client, createOpts).Extract()
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	t.Logf("Successfully created container: %s", container.ContainerRef)
   321  
   322  	containerID, err := ParseID(container.ContainerRef)
   323  	if err != nil {
   324  		return nil, err
   325  	}
   326  
   327  	container, err = containers.Get(client, containerID).Extract()
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  
   332  	tools.PrintResource(t, container)
   333  
   334  	th.AssertEquals(t, container.Name, containerName)
   335  	th.AssertEquals(t, container.Type, "generic")
   336  
   337  	return container, nil
   338  }
   339  
   340  // ReplaceGenericContainerSecretRef will replace the container old secret
   341  // reference with a new one. An error will be returned if the reference could
   342  // not be replaced.
   343  func ReplaceGenericContainerSecretRef(t *testing.T, client *gophercloud.ServiceClient, container *containers.Container, secretOld *secrets.Secret, secretNew *secrets.Secret) error {
   344  	containerID, err := ParseID(container.ContainerRef)
   345  	if err != nil {
   346  		return err
   347  	}
   348  
   349  	t.Logf("Attempting to remove an old secret reference %s", secretOld.SecretRef)
   350  
   351  	res1 := containers.DeleteSecretRef(client, containerID, containers.SecretRef{Name: secretOld.Name, SecretRef: secretOld.SecretRef})
   352  	if res1.Err != nil {
   353  		return res1.Err
   354  	}
   355  
   356  	t.Logf("Successfully removed old secret reference: %s", secretOld.SecretRef)
   357  
   358  	t.Logf("Attempting to remove a new secret reference %s", secretNew.SecretRef)
   359  
   360  	newRef := containers.SecretRef{Name: secretNew.Name, SecretRef: secretNew.SecretRef}
   361  	res2 := containers.CreateSecretRef(client, containerID, newRef)
   362  	if res2.Err != nil {
   363  		return res2.Err
   364  	}
   365  
   366  	c, err := res2.Extract()
   367  	if err != nil {
   368  		return err
   369  	}
   370  	tools.PrintResource(t, c)
   371  
   372  	t.Logf("Successfully created new secret reference: %s", secretNew.SecretRef)
   373  
   374  	updatedContainer, err := containers.Get(client, containerID).Extract()
   375  	if err != nil {
   376  		return err
   377  	}
   378  
   379  	tools.PrintResource(t, container)
   380  
   381  	th.AssertEquals(t, updatedContainer.Name, container.Name)
   382  	th.AssertEquals(t, updatedContainer.Type, container.Type)
   383  	th.AssertEquals(t, updatedContainer.SecretRefs[0], newRef)
   384  
   385  	return nil
   386  }
   387  
   388  // CreatePassphraseSecret will create a random passphrase secret.
   389  // An error will be returned if the secret could not be created.
   390  func CreatePassphraseSecret(t *testing.T, client *gophercloud.ServiceClient, passphrase string) (*secrets.Secret, error) {
   391  	secretName := tools.RandomString("TESTACC-", 8)
   392  
   393  	t.Logf("Attempting to create secret %s", secretName)
   394  
   395  	createOpts := secrets.CreateOpts{
   396  		Algorithm:          "aes",
   397  		BitLength:          256,
   398  		Mode:               "cbc",
   399  		Name:               secretName,
   400  		Payload:            passphrase,
   401  		PayloadContentType: "text/plain",
   402  		SecretType:         secrets.PassphraseSecret,
   403  	}
   404  
   405  	secret, err := secrets.Create(client, createOpts).Extract()
   406  	if err != nil {
   407  		return nil, err
   408  	}
   409  
   410  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   411  
   412  	secretID, err := ParseID(secret.SecretRef)
   413  	if err != nil {
   414  		return nil, err
   415  	}
   416  
   417  	secret, err = secrets.Get(client, secretID).Extract()
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  
   422  	tools.PrintResource(t, secret)
   423  
   424  	th.AssertEquals(t, secret.Name, secretName)
   425  	th.AssertEquals(t, secret.Algorithm, "aes")
   426  
   427  	return secret, nil
   428  }
   429  
   430  // CreatePublicSecret will create a random public secret. An error
   431  // will be returned if the secret could not be created.
   432  func CreatePublicSecret(t *testing.T, client *gophercloud.ServiceClient, pub []byte) (*secrets.Secret, error) {
   433  	b64Cert := base64.StdEncoding.EncodeToString(pub)
   434  
   435  	name := tools.RandomString("TESTACC-", 8)
   436  	t.Logf("Attempting to create public key %s", name)
   437  
   438  	createOpts := secrets.CreateOpts{
   439  		Name:                   name,
   440  		SecretType:             secrets.PublicSecret,
   441  		Payload:                b64Cert,
   442  		PayloadContentType:     "application/octet-stream",
   443  		PayloadContentEncoding: "base64",
   444  		Algorithm:              "rsa",
   445  	}
   446  
   447  	secret, err := secrets.Create(client, createOpts).Extract()
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  
   452  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   453  
   454  	secretID, err := ParseID(secret.SecretRef)
   455  	if err != nil {
   456  		return nil, err
   457  	}
   458  
   459  	secret, err = secrets.Get(client, secretID).Extract()
   460  	if err != nil {
   461  		return nil, err
   462  	}
   463  
   464  	tools.PrintResource(t, secret)
   465  
   466  	th.AssertEquals(t, secret.Name, name)
   467  	th.AssertEquals(t, secret.Algorithm, "rsa")
   468  
   469  	return secret, nil
   470  }
   471  
   472  // CreatePrivateSecret will create a random private secret. An error
   473  // will be returned if the secret could not be created.
   474  func CreatePrivateSecret(t *testing.T, client *gophercloud.ServiceClient, priv []byte) (*secrets.Secret, error) {
   475  	b64Cert := base64.StdEncoding.EncodeToString(priv)
   476  
   477  	name := tools.RandomString("TESTACC-", 8)
   478  	t.Logf("Attempting to create public key %s", name)
   479  
   480  	createOpts := secrets.CreateOpts{
   481  		Name:                   name,
   482  		SecretType:             secrets.PrivateSecret,
   483  		Payload:                b64Cert,
   484  		PayloadContentType:     "application/octet-stream",
   485  		PayloadContentEncoding: "base64",
   486  		Algorithm:              "rsa",
   487  	}
   488  
   489  	secret, err := secrets.Create(client, createOpts).Extract()
   490  	if err != nil {
   491  		return nil, err
   492  	}
   493  
   494  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   495  
   496  	secretID, err := ParseID(secret.SecretRef)
   497  	if err != nil {
   498  		return nil, err
   499  	}
   500  
   501  	secret, err = secrets.Get(client, secretID).Extract()
   502  	if err != nil {
   503  		return nil, err
   504  	}
   505  
   506  	tools.PrintResource(t, secret)
   507  
   508  	th.AssertEquals(t, secret.Name, name)
   509  	th.AssertEquals(t, secret.Algorithm, "rsa")
   510  
   511  	return secret, nil
   512  }
   513  
   514  // CreateSecretWithPayload will create a random secret with a given payload.
   515  // An error will be returned if the secret could not be created.
   516  func CreateSecretWithPayload(t *testing.T, client *gophercloud.ServiceClient, payload string) (*secrets.Secret, error) {
   517  	secretName := tools.RandomString("TESTACC-", 8)
   518  
   519  	t.Logf("Attempting to create secret %s", secretName)
   520  
   521  	expiration := time.Date(2049, 1, 1, 1, 1, 1, 0, time.UTC)
   522  	createOpts := secrets.CreateOpts{
   523  		Algorithm:          "aes",
   524  		BitLength:          256,
   525  		Mode:               "cbc",
   526  		Name:               secretName,
   527  		Payload:            payload,
   528  		PayloadContentType: "text/plain",
   529  		SecretType:         secrets.OpaqueSecret,
   530  		Expiration:         &expiration,
   531  	}
   532  
   533  	secret, err := secrets.Create(client, createOpts).Extract()
   534  	if err != nil {
   535  		return nil, err
   536  	}
   537  
   538  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   539  
   540  	secretID, err := ParseID(secret.SecretRef)
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  
   545  	secret, err = secrets.Get(client, secretID).Extract()
   546  	if err != nil {
   547  		return nil, err
   548  	}
   549  
   550  	tools.PrintResource(t, secret)
   551  
   552  	th.AssertEquals(t, secret.Name, secretName)
   553  	th.AssertEquals(t, secret.Algorithm, "aes")
   554  	th.AssertEquals(t, secret.Expiration, expiration)
   555  
   556  	return secret, nil
   557  }
   558  
   559  // CreateSymmetricSecret will create a random symmetric secret. An error
   560  // will be returned if the secret could not be created.
   561  func CreateSymmetricSecret(t *testing.T, client *gophercloud.ServiceClient) (*secrets.Secret, error) {
   562  	name := tools.RandomString("TESTACC-", 8)
   563  	key := tools.RandomString("", 256)
   564  	b64Key := base64.StdEncoding.EncodeToString([]byte(key))
   565  
   566  	t.Logf("Attempting to create symmetric key %s", name)
   567  
   568  	createOpts := secrets.CreateOpts{
   569  		Name:                   name,
   570  		SecretType:             secrets.SymmetricSecret,
   571  		Payload:                b64Key,
   572  		PayloadContentType:     "application/octet-stream",
   573  		PayloadContentEncoding: "base64",
   574  		Algorithm:              "aes",
   575  		BitLength:              256,
   576  		Mode:                   "cbc",
   577  	}
   578  
   579  	secret, err := secrets.Create(client, createOpts).Extract()
   580  	if err != nil {
   581  		return nil, err
   582  	}
   583  
   584  	t.Logf("Successfully created secret: %s", secret.SecretRef)
   585  
   586  	secretID, err := ParseID(secret.SecretRef)
   587  	if err != nil {
   588  		return nil, err
   589  	}
   590  
   591  	secret, err = secrets.Get(client, secretID).Extract()
   592  	if err != nil {
   593  		return nil, err
   594  	}
   595  
   596  	tools.PrintResource(t, secret)
   597  
   598  	th.AssertEquals(t, secret.Name, name)
   599  	th.AssertEquals(t, secret.Algorithm, "aes")
   600  
   601  	return secret, nil
   602  }
   603  
   604  // DeleteContainer will delete a container. A fatal error will occur if the
   605  // container could not be deleted. This works best when used as a deferred
   606  // function.
   607  func DeleteContainer(t *testing.T, client *gophercloud.ServiceClient, id string) {
   608  	t.Logf("Attempting to delete container %s", id)
   609  
   610  	err := containers.Delete(client, id).ExtractErr()
   611  	if err != nil {
   612  		t.Fatalf("Could not delete container: %s", err)
   613  	}
   614  
   615  	t.Logf("Successfully deleted container %s", id)
   616  }
   617  
   618  // DeleteOrder will delete an order. A fatal error will occur if the
   619  // order could not be deleted. This works best when used as a deferred
   620  // function.
   621  func DeleteOrder(t *testing.T, client *gophercloud.ServiceClient, id string) {
   622  	t.Logf("Attempting to delete order %s", id)
   623  
   624  	err := orders.Delete(client, id).ExtractErr()
   625  	if err != nil {
   626  		t.Fatalf("Could not delete order: %s", err)
   627  	}
   628  
   629  	t.Logf("Successfully deleted order %s", id)
   630  }
   631  
   632  // DeleteSecret will delete a secret. A fatal error will occur if the secret
   633  // could not be deleted. This works best when used as a deferred function.
   634  func DeleteSecret(t *testing.T, client *gophercloud.ServiceClient, id string) {
   635  	t.Logf("Attempting to delete secret %s", id)
   636  
   637  	err := secrets.Delete(client, id).ExtractErr()
   638  	if err != nil {
   639  		t.Fatalf("Could not delete secret: %s", err)
   640  	}
   641  
   642  	t.Logf("Successfully deleted secret %s", id)
   643  }
   644  
   645  func ParseID(ref string) (string, error) {
   646  	parts := strings.Split(ref, "/")
   647  	if len(parts) < 2 {
   648  		return "", fmt.Errorf("Could not parse %s", ref)
   649  	}
   650  
   651  	return parts[len(parts)-1], nil
   652  }
   653  
   654  // CreateCertificate will create a random certificate. A fatal error will
   655  // be returned if creation failed.
   656  // https://golang.org/src/crypto/tls/generate_cert.go
   657  func CreateCertificate(t *testing.T, passphrase string) ([]byte, []byte, error) {
   658  	key, err := rsa.GenerateKey(rand.Reader, 2048)
   659  	if err != nil {
   660  		return nil, nil, err
   661  	}
   662  
   663  	block := &pem.Block{
   664  		Type:  "RSA PRIVATE KEY",
   665  		Bytes: x509.MarshalPKCS1PrivateKey(key),
   666  	}
   667  
   668  	if passphrase != "" {
   669  		block, err = x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, []byte(passphrase), x509.PEMCipherAES256)
   670  		if err != nil {
   671  			return nil, nil, err
   672  		}
   673  	}
   674  
   675  	keyPem := pem.EncodeToMemory(block)
   676  
   677  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
   678  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
   679  	if err != nil {
   680  		return nil, nil, err
   681  	}
   682  
   683  	tpl := x509.Certificate{
   684  		SerialNumber: serialNumber,
   685  		Subject: pkix.Name{
   686  			Organization: []string{"Some Org"},
   687  		},
   688  		NotBefore:             time.Now(),
   689  		NotAfter:              time.Now().AddDate(5, 0, 0),
   690  		BasicConstraintsValid: true,
   691  	}
   692  
   693  	cert, err := x509.CreateCertificate(rand.Reader, &tpl, &tpl, &key.PublicKey, key)
   694  	if err != nil {
   695  		return nil, nil, err
   696  	}
   697  
   698  	certPem := pem.EncodeToMemory(&pem.Block{
   699  		Type:  "CERTIFICATE",
   700  		Bytes: cert,
   701  	})
   702  
   703  	return keyPem, certPem, nil
   704  }
   705  
   706  // CreateRSAKeyPair will create a random RSA key pair. An error will be
   707  // returned if the pair could not be created.
   708  func CreateRSAKeyPair(t *testing.T, passphrase string) ([]byte, []byte, error) {
   709  	key, err := rsa.GenerateKey(rand.Reader, 2048)
   710  	if err != nil {
   711  		return nil, nil, err
   712  	}
   713  
   714  	block := &pem.Block{
   715  		Type:  "RSA PRIVATE KEY",
   716  		Bytes: x509.MarshalPKCS1PrivateKey(key),
   717  	}
   718  
   719  	if passphrase != "" {
   720  		block, err = x509.EncryptPEMBlock(rand.Reader, block.Type, block.Bytes, []byte(passphrase), x509.PEMCipherAES256)
   721  		if err != nil {
   722  			return nil, nil, err
   723  		}
   724  	}
   725  
   726  	keyPem := pem.EncodeToMemory(block)
   727  
   728  	asn1Bytes, err := asn1.Marshal(key.PublicKey)
   729  	if err != nil {
   730  		return nil, nil, err
   731  	}
   732  
   733  	block = &pem.Block{
   734  		Type:  "RSA PUBLIC KEY",
   735  		Bytes: asn1Bytes,
   736  	}
   737  
   738  	pubPem := pem.EncodeToMemory(block)
   739  
   740  	return keyPem, pubPem, nil
   741  }
   742  
   743  func WaitForOrder(client *gophercloud.ServiceClient, orderID string) error {
   744  	return tools.WaitFor(func() (bool, error) {
   745  		order, err := orders.Get(client, orderID).Extract()
   746  		if err != nil {
   747  			return false, err
   748  		}
   749  
   750  		if order.SecretRef != "" {
   751  			return true, nil
   752  		}
   753  
   754  		if order.ContainerRef != "" {
   755  			return true, nil
   756  		}
   757  
   758  		if order.Status == "ERROR" {
   759  			return false, fmt.Errorf("Order %s in ERROR state", orderID)
   760  		}
   761  
   762  		return false, nil
   763  	})
   764  }