github.com/letsencrypt/boulder@v0.20251208.0/test/integration/common_test.go (about)

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