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 }