136 lines
4.0 KiB
Go
136 lines
4.0 KiB
Go
// +build integration
|
|
|
|
package integration
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"log"
|
|
"math/big"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/letsencrypt/pkcs11key/v4"
|
|
)
|
|
|
|
var template = `[AUDIT] Failed RPC to store at SA, orphaning precertificate: serial=[%x] cert=[%x] err=[sa.StorageAuthority.AddCertificate timed out after 5000 ms], issuerID=[1], regID=[1], orderID=[1]
|
|
[AUDIT] Failed RPC to store at SA, orphaning certificate: serial=[%x] cert=[%x] err=[sa.StorageAuthority.AddCertificate timed out after 5000 ms], issuerID=[1], regID=[1], orderID=[1]`
|
|
|
|
// TestOrphanFinder runs the orphan-finder with an example input file. This must
|
|
// be run after other tests so the account ID 1 exists (since the inserted
|
|
// certificates will be associated with that account).
|
|
func TestOrphanFinder(t *testing.T) {
|
|
t.Parallel()
|
|
precert, err := makeFakeCert(true)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
cert, err := makeFakeCert(false)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
f, _ := ioutil.TempFile("", "orphaned.log")
|
|
io.WriteString(f, fmt.Sprintf(template, precert.SerialNumber.Bytes(),
|
|
precert.Raw, cert.SerialNumber.Bytes(), cert.Raw))
|
|
f.Close()
|
|
cmd := exec.Command("./bin/orphan-finder", "parse-ca-log",
|
|
"--config", "./"+os.Getenv("BOULDER_CONFIG_DIR")+"/orphan-finder.json",
|
|
"--log-file", f.Name())
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
t.Fatalf("orphan finder failed (%s). Output was: %s", err, out)
|
|
}
|
|
if !strings.Contains(string(out), "Found 1 precertificate orphans and added 1 to the database") {
|
|
t.Fatalf("Failed to insert orphaned precertificate. orphan-finder output was: %s", out)
|
|
}
|
|
if !strings.Contains(string(out), "Found 1 certificate orphans and added 1 to the database") {
|
|
t.Fatalf("Failed to insert orphaned certificate. orphan-finder output was: %s", out)
|
|
}
|
|
}
|
|
|
|
// makeFakeCert a unique fake cert for each run of TestOrphanFinder to avoid duplicate
|
|
// errors. This fake cert will have its issuer equal to the issuer we use in the
|
|
// general integration test setup, and will be signed by that issuer key.
|
|
// Otherwise, the request orphan-finder makes to sign OCSP would be rejected.
|
|
func makeFakeCert(precert bool) (*x509.Certificate, error) {
|
|
serialBytes := make([]byte, 18)
|
|
_, err := rand.Read(serialBytes[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
serial := big.NewInt(0)
|
|
serial.SetBytes(serialBytes)
|
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pubKeyBytes, err := ioutil.ReadFile("/tmp/intermediate-signing-pub-rsa.pem")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
block, _ := pem.Decode(pubKeyBytes)
|
|
if block == nil {
|
|
return nil, fmt.Errorf("no PEM found")
|
|
}
|
|
pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("parsing issuer public key: %s", err)
|
|
}
|
|
var pkcs11Config pkcs11key.Config
|
|
contents, err := ioutil.ReadFile("test/test-ca.key-pkcs11.json")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if err = json.Unmarshal(contents, &pkcs11Config); err != nil {
|
|
return nil, err
|
|
}
|
|
signer, err := pkcs11key.NewPool(1, pkcs11Config.Module,
|
|
pkcs11Config.TokenLabel, pkcs11Config.PIN, pubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
issuerTemplate := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "CA intermediate (RSA) A",
|
|
},
|
|
}
|
|
template := &x509.Certificate{
|
|
Subject: pkix.Name{
|
|
CommonName: "fake cert for TestOrphanFinder",
|
|
},
|
|
SerialNumber: serial,
|
|
NotBefore: time.Now(),
|
|
NotAfter: time.Now().AddDate(0, 90, 0),
|
|
DNSNames: []string{"fakecert.example.com"},
|
|
}
|
|
if precert {
|
|
template.ExtraExtensions = []pkix.Extension{
|
|
pkix.Extension{
|
|
Id: OIDExtensionCTPoison,
|
|
Critical: true,
|
|
Value: []byte{5, 0},
|
|
},
|
|
}
|
|
}
|
|
|
|
der, err := x509.CreateCertificate(rand.Reader, template, issuerTemplate, key.Public(), signer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cert, err := x509.ParseCertificate(der)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cert, err
|
|
}
|