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

     1  package main
     2  
     3  import (
     4  	"crypto/rand"
     5  	"crypto/rsa"
     6  	"crypto/x509"
     7  	"crypto/x509/pkix"
     8  	"encoding/pem"
     9  	"fmt"
    10  	"log"
    11  	"math/big"
    12  	"os"
    13  )
    14  
    15  const (
    16  	// bits is the size of the resulting RSA key, also known as "nlen" or "Length
    17  	// of the modulus N". Usually 1024, 2048, or 4096.
    18  	bits = 2048
    19  	// gap is the exponent of the different between the prime factors of the RSA
    20  	// key, i.e. |p-q| ~= 2^gap. For FIPS compliance, set this to (bits/2 - 100).
    21  	gap = 516
    22  )
    23  
    24  func main() {
    25  	// Generate q, which will be the smaller of the two factors. We set its length
    26  	// so that the product of two similarly-sized factors will be the desired
    27  	// bit length.
    28  	q, err := rand.Prime(rand.Reader, (bits+1)/2)
    29  	if err != nil {
    30  		log.Fatalln(err)
    31  	}
    32  
    33  	// Our starting point for p is q + 2^gap.
    34  	p := new(big.Int).Add(q, new(big.Int).Exp(big.NewInt(2), big.NewInt(gap), nil))
    35  
    36  	// Now we just keep incrementing P until we find a prime. You might think
    37  	// this would take a while, but it won't: there are a lot of primes.
    38  	attempts := 0
    39  	for {
    40  		// Using 34 rounds of Miller-Rabin primality testing is enough for the go
    41  		// stdlib, so it's enough for us.
    42  		if p.ProbablyPrime(34) {
    43  			break
    44  		}
    45  
    46  		// We know P is odd because it started as a prime (odd) plus a power of two
    47  		// (even), so we can increment by 2 to remain odd.
    48  		p.Add(p, big.NewInt(2))
    49  		attempts++
    50  	}
    51  
    52  	fmt.Println("p:", p.String())
    53  	fmt.Println("q:", q.String())
    54  	fmt.Println("Differ by", fmt.Sprintf("2^%d + %d", gap, 2*attempts))
    55  
    56  	// Construct the public modulus N from the prime factors.
    57  	n := new(big.Int).Mul(p, q)
    58  
    59  	// Construct the public key from the modulus and (fixed) public exponent.
    60  	pubkey := rsa.PublicKey{
    61  		N: n,
    62  		E: 65537,
    63  	}
    64  
    65  	// Construct the private exponent D from the prime factors.
    66  	p_1 := new(big.Int).Sub(p, big.NewInt(1))
    67  	q_1 := new(big.Int).Sub(q, big.NewInt(1))
    68  	field := new(big.Int).Mul(p_1, q_1)
    69  	d := new(big.Int).ModInverse(big.NewInt(65537), field)
    70  
    71  	// Construct the private key from the factors and private exponent.
    72  	privkey := rsa.PrivateKey{
    73  		PublicKey: pubkey,
    74  		D:         d,
    75  		Primes:    []*big.Int{p, q},
    76  	}
    77  	privkey.Precompute()
    78  
    79  	// Sign a CSR using this key, so we can use it in integration tests.
    80  	// Note that this step *only works on go1.23 and earlier*. Later versions of
    81  	// go detect that the prime factors are too close together and refuse to
    82  	// produce a signature.
    83  	csrDER, err := x509.CreateCertificateRequest(
    84  		rand.Reader,
    85  		&x509.CertificateRequest{
    86  			Subject:   pkix.Name{CommonName: "example.com"},
    87  			PublicKey: &pubkey,
    88  		},
    89  		&privkey)
    90  	if err != nil {
    91  		log.Fatalln(err)
    92  	}
    93  
    94  	csrPEM := pem.EncodeToMemory(&pem.Block{
    95  		Type:  "CERTIFICATE REQUEST",
    96  		Bytes: csrDER,
    97  	})
    98  	fmt.Fprint(os.Stdout, string(csrPEM))
    99  }