github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/internal/acceptance/openstack/keymanager/v1/keymanager.go (about)

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