...

Source file src/github.com/letsencrypt/boulder/test/integration/common_test.go

Documentation: github.com/letsencrypt/boulder/test/integration

     1  //go:build integration
     2  
     3  package integration
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/ecdsa"
     8  	"crypto/elliptic"
     9  	"crypto/rand"
    10  	"crypto/x509"
    11  	"crypto/x509/pkix"
    12  	"encoding/asn1"
    13  	"encoding/hex"
    14  	"fmt"
    15  	"net/http"
    16  	"os"
    17  
    18  	"github.com/eggsampler/acme/v3"
    19  )
    20  
    21  func init() {
    22  	// Go tests get run in the directory their source code lives in. For these
    23  	// test cases, that would be "test/integration." However, it's easier to
    24  	// reference test data and config files for integration tests relative to the
    25  	// root of the Boulder repo, so we run all of these tests from there instead.
    26  	os.Chdir("../../")
    27  }
    28  
    29  var (
    30  	OIDExtensionCTPoison = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
    31  )
    32  
    33  func random_domain() string {
    34  	var bytes [3]byte
    35  	rand.Read(bytes[:])
    36  	return hex.EncodeToString(bytes[:]) + ".com"
    37  }
    38  
    39  type client struct {
    40  	acme.Account
    41  	acme.Client
    42  }
    43  
    44  func makeClient(contacts ...string) (*client, error) {
    45  	c, err := acme.NewClient("http://boulder.service.consul:4001/directory")
    46  	if err != nil {
    47  		return nil, fmt.Errorf("Error connecting to acme directory: %v", err)
    48  	}
    49  	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    50  	if err != nil {
    51  		return nil, fmt.Errorf("error creating private key: %v", err)
    52  	}
    53  	account, err := c.NewAccount(privKey, false, true, contacts...)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	return &client{account, c}, nil
    58  }
    59  
    60  func addHTTP01Response(token, keyAuthorization string) error {
    61  	resp, err := http.Post("http://boulder.service.consul:8055/add-http01", "",
    62  		bytes.NewBufferString(fmt.Sprintf(`{
    63  		"token": "%s",
    64  		"content": "%s"
    65  	}`, token, keyAuthorization)))
    66  	if err != nil {
    67  		return fmt.Errorf("adding http-01 response: %s", err)
    68  	}
    69  	if resp.StatusCode != http.StatusOK {
    70  		return fmt.Errorf("adding http-01 response: status %d", resp.StatusCode)
    71  	}
    72  	resp.Body.Close()
    73  	return nil
    74  }
    75  
    76  func delHTTP01Response(token string) error {
    77  	resp, err := http.Post("http://boulder.service.consul:8055/del-http01", "",
    78  		bytes.NewBufferString(fmt.Sprintf(`{
    79  		"token": "%s"
    80  	}`, token)))
    81  	if err != nil {
    82  		return fmt.Errorf("deleting http-01 response: %s", err)
    83  	}
    84  	defer resp.Body.Close()
    85  
    86  	if resp.StatusCode != http.StatusOK {
    87  		return fmt.Errorf("deleting http-01 response: status %d", resp.StatusCode)
    88  	}
    89  	return nil
    90  }
    91  
    92  func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, domains []string, cn bool) (*client, *acme.Order, error) {
    93  	var err error
    94  	if c == nil {
    95  		c, err = makeClient()
    96  		if err != nil {
    97  			return nil, nil, err
    98  		}
    99  	}
   100  
   101  	var ids []acme.Identifier
   102  	for _, domain := range domains {
   103  		ids = append(ids, acme.Identifier{Type: "dns", Value: domain})
   104  	}
   105  	order, err := c.Client.NewOrder(c.Account, ids)
   106  	if err != nil {
   107  		return nil, nil, err
   108  	}
   109  
   110  	for _, authUrl := range order.Authorizations {
   111  		auth, err := c.Client.FetchAuthorization(c.Account, authUrl)
   112  		if err != nil {
   113  			return nil, nil, fmt.Errorf("fetching authorization at %s: %s", authUrl, err)
   114  		}
   115  
   116  		chal, ok := auth.ChallengeMap[acme.ChallengeTypeHTTP01]
   117  		if !ok {
   118  			return nil, nil, fmt.Errorf("no HTTP challenge at %s", authUrl)
   119  		}
   120  
   121  		err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
   122  		if err != nil {
   123  			return nil, nil, fmt.Errorf("adding HTTP-01 response: %s", err)
   124  		}
   125  		chal, err = c.Client.UpdateChallenge(c.Account, chal)
   126  		if err != nil {
   127  			delHTTP01Response(chal.Token)
   128  			return nil, nil, fmt.Errorf("updating challenge: %s", err)
   129  		}
   130  		delHTTP01Response(chal.Token)
   131  	}
   132  
   133  	csr, err := makeCSR(csrKey, domains, cn)
   134  	if err != nil {
   135  		return nil, nil, err
   136  	}
   137  
   138  	order, err = c.Client.FinalizeOrder(c.Account, order, csr)
   139  	if err != nil {
   140  		return nil, nil, fmt.Errorf("finalizing order: %s", err)
   141  	}
   142  
   143  	return c, &order, nil
   144  }
   145  
   146  type issuanceResult struct {
   147  	acme.Order
   148  	certs []*x509.Certificate
   149  }
   150  
   151  func authAndIssue(c *client, csrKey *ecdsa.PrivateKey, domains []string, cn bool) (*issuanceResult, error) {
   152  	var err error
   153  
   154  	c, order, err := makeClientAndOrder(c, csrKey, domains, cn)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	certs, err := c.Client.FetchCertificates(c.Account, order.Certificate)
   160  	if err != nil {
   161  		return nil, fmt.Errorf("fetching certificates: %s", err)
   162  	}
   163  	return &issuanceResult{*order, certs}, nil
   164  }
   165  
   166  type issuanceResultAllChains struct {
   167  	acme.Order
   168  	certs map[string][]*x509.Certificate
   169  }
   170  
   171  func authAndIssueFetchAllChains(c *client, csrKey *ecdsa.PrivateKey, domains []string, cn bool) (*issuanceResultAllChains, error) {
   172  	c, order, err := makeClientAndOrder(c, csrKey, domains, cn)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	// Retrieve all the certificate chains served by the WFE2.
   178  	certs, err := c.Client.FetchAllCertificates(c.Account, order.Certificate)
   179  	if err != nil {
   180  		return nil, fmt.Errorf("fetching certificates: %s", err)
   181  	}
   182  
   183  	return &issuanceResultAllChains{*order, certs}, nil
   184  }
   185  
   186  func makeCSR(k *ecdsa.PrivateKey, domains []string, cn bool) (*x509.CertificateRequest, error) {
   187  	var err error
   188  	if k == nil {
   189  		k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   190  		if err != nil {
   191  			return nil, fmt.Errorf("generating certificate key: %s", err)
   192  		}
   193  	}
   194  
   195  	tmpl := &x509.CertificateRequest{
   196  		SignatureAlgorithm: x509.ECDSAWithSHA256,
   197  		PublicKeyAlgorithm: x509.ECDSA,
   198  		PublicKey:          k.Public(),
   199  		DNSNames:           domains,
   200  	}
   201  	if cn {
   202  		tmpl.Subject = pkix.Name{CommonName: domains[0]}
   203  	}
   204  
   205  	csrDer, err := x509.CreateCertificateRequest(rand.Reader, tmpl, k)
   206  	if err != nil {
   207  		return nil, fmt.Errorf("making csr: %s", err)
   208  	}
   209  	csr, err := x509.ParseCertificateRequest(csrDer)
   210  	if err != nil {
   211  		return nil, fmt.Errorf("parsing csr: %s", err)
   212  	}
   213  	return csr, nil
   214  }
   215  

View as plain text