boulder/test/integration/testdata/fermat_csr.go

100 lines
2.7 KiB
Go

package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"os"
)
const (
// bits is the size of the resulting RSA key, also known as "nlen" or "Length
// of the modulus N". Usually 1024, 2048, or 4096.
bits = 2048
// gap is the exponent of the different between the prime factors of the RSA
// key, i.e. |p-q| ~= 2^gap. For FIPS compliance, set this to (bits/2 - 100).
gap = 516
)
func main() {
// Generate q, which will be the smaller of the two factors. We set its length
// so that the product of two similarly-sized factors will be the desired
// bit length.
q, err := rand.Prime(rand.Reader, (bits+1)/2)
if err != nil {
log.Fatalln(err)
}
// Our starting point for p is q + 2^gap.
p := new(big.Int).Add(q, new(big.Int).Exp(big.NewInt(2), big.NewInt(gap), nil))
// Now we just keep incrementing P until we find a prime. You might think
// this would take a while, but it won't: there are a lot of primes.
attempts := 0
for {
// Using 34 rounds of Miller-Rabin primality testing is enough for the go
// stdlib, so it's enough for us.
if p.ProbablyPrime(34) {
break
}
// We know P is odd because it started as a prime (odd) plus a power of two
// (even), so we can increment by 2 to remain odd.
p.Add(p, big.NewInt(2))
attempts++
}
fmt.Println("p:", p.String())
fmt.Println("q:", q.String())
fmt.Println("Differ by", fmt.Sprintf("2^%d + %d", gap, 2*attempts))
// Construct the public modulus N from the prime factors.
n := new(big.Int).Mul(p, q)
// Construct the public key from the modulus and (fixed) public exponent.
pubkey := rsa.PublicKey{
N: n,
E: 65537,
}
// Construct the private exponent D from the prime factors.
p_1 := new(big.Int).Sub(p, big.NewInt(1))
q_1 := new(big.Int).Sub(q, big.NewInt(1))
field := new(big.Int).Mul(p_1, q_1)
d := new(big.Int).ModInverse(big.NewInt(65537), field)
// Construct the private key from the factors and private exponent.
privkey := rsa.PrivateKey{
PublicKey: pubkey,
D: d,
Primes: []*big.Int{p, q},
}
privkey.Precompute()
// Sign a CSR using this key, so we can use it in integration tests.
// Note that this step *only works on go1.23 and earlier*. Later versions of
// go detect that the prime factors are too close together and refuse to
// produce a signature.
csrDER, err := x509.CreateCertificateRequest(
rand.Reader,
&x509.CertificateRequest{
Subject: pkix.Name{CommonName: "example.com"},
PublicKey: &pubkey,
},
&privkey)
if err != nil {
log.Fatalln(err)
}
csrPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE REQUEST",
Bytes: csrDER,
})
fmt.Fprint(os.Stdout, string(csrPEM))
}