func TestCreateSelfSignedCert(t *testing.T) { // --- TEST: Create a self-signed certificate from a CSR. --- // // Generate a self-signed certificate from the request. encodedCertFromCode, _, err := CreateSelfSignedCert(CARequest) if err != nil { t.Fatal(err.Error()) } // Now compare to a pre-made certificate made using a JSON file with the // same request information. This JSON file is located in testdata/initCA // and is called ca_csr.json. CLIOutputFile := preMadeOutput CLIOutput, err := ioutil.ReadFile(CLIOutputFile) if err != nil { t.Fatal(err.Error()) } encodedCertFromCLI, err := cleanCLIOutput(CLIOutput, "cert") if err != nil { t.Fatal(err.Error()) } certFromCode, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCode) if err != nil { t.Fatal(err.Error()) } certFromCLI, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCLI) if err != nil { t.Fatal(err.Error()) } // Nullify any fields of the certificates which are dependent upon the time // of the certificate's creation. nullifyTimeDependency(certFromCode) nullifyTimeDependency(certFromCLI) if !reflect.DeepEqual(certFromCode, certFromCLI) { unequalFields := checkFields( *certFromCode, *certFromCLI, reflect.TypeOf(*certFromCode)) t.Log("The following fields were unequal:") for _, field := range unequalFields { t.Log(field) } t.Fatal("Certificates unequal.") } }
// Sign signs a new certificate based on the PEM-encoded client // certificate or certificate request with the signing profile, specified by profileName. // The certificate will be valid for the host named in the hostName parameter. func (s *Signer) Sign(hostName string, in []byte, profileName string) (cert []byte, err error) { profile := s.Policy.Profiles[profileName] block, _ := pem.Decode(in) if block == nil { return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed, err) } var template *x509.Certificate switch block.Type { case "CERTIFICATE": template, err = helpers.ParseSelfSignedCertificatePEM(in) case "CERTIFICATE REQUEST": template, err = s.parseCertificateRequest(block.Bytes) default: return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed, errors.New("Not a certificate or csr.")) } if err != nil { return } if ip := net.ParseIP(hostName); ip != nil { template.IPAddresses = []net.IP{ip} } else { template.DNSNames = []string{hostName} } return s.sign(template, profile) }
// NewRootCA creates a new RootCA object from unparsed cert and key byte // slices. key may be nil, and in this case NewRootCA will return a RootCA // without a signer. func NewRootCA(cert, key []byte, certExpiry time.Duration) (RootCA, error) { // Check to see if the Certificate file is a valid, self-signed Cert parsedCA, err := helpers.ParseSelfSignedCertificatePEM(cert) if err != nil { return RootCA{}, err } // Calculate the digest for our RootCACertificate digest := digest.FromBytes(cert) // Create a Pool with our RootCACertificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(cert) { return RootCA{}, fmt.Errorf("error while adding root CA cert to Cert Pool") } if len(key) == 0 { // This RootCA does not have a valid signer. return RootCA{Cert: cert, Digest: digest, Pool: pool}, nil } var ( passphraseStr string passphrase, passphrasePrev []byte priv crypto.Signer ) // Attempt two distinct passphrases, so we can do a hitless passphrase rotation if passphraseStr = os.Getenv(PassphraseENVVar); passphraseStr != "" { passphrase = []byte(passphraseStr) } if p := os.Getenv(PassphraseENVVarPrev); p != "" { passphrasePrev = []byte(p) } // Attempt to decrypt the current private-key with the passphrases provided priv, err = helpers.ParsePrivateKeyPEMWithPassword(key, passphrase) if err != nil { priv, err = helpers.ParsePrivateKeyPEMWithPassword(key, passphrasePrev) if err != nil { log.Debug("Malformed private key %v", err) return RootCA{}, err } } if err := ensureCertKeyMatch(parsedCA, priv.Public()); err != nil { return RootCA{}, err } signer, err := local.NewSigner(priv, parsedCA, cfsigner.DefaultSigAlgo(priv), SigningPolicy(certExpiry)) if err != nil { return RootCA{}, err } // If the key was loaded from disk unencrypted, but there is a passphrase set, // ensure it is encrypted, so it doesn't hit raft in plain-text keyBlock, _ := pem.Decode(key) if keyBlock == nil { // This RootCA does not have a valid signer. return RootCA{Cert: cert, Digest: digest, Pool: pool}, nil } if passphraseStr != "" && !x509.IsEncryptedPEMBlock(keyBlock) { key, err = EncryptECPrivateKey(key, passphraseStr) if err != nil { return RootCA{}, err } } return RootCA{Signer: signer, Key: key, Digest: digest, Cert: cert, Pool: pool}, nil }
func TestCreateSelfSignedCert(t *testing.T) { // --- TEST: Create a self-signed certificate from a CSR. --- // // Make the request we will use to generate the certificate. keyRequest := csr.KeyRequest{ Algo: "rsa", Size: 2048, } CAConfig := csr.CAConfig{ PathLength: 1, Expiry: "1/1/2015", } request := csr.CertificateRequest{ CN: "example.com", Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "Internet Widgets, LLC", OU: "Certificate Authority", }, }, Hosts: []string{"ca.example.com"}, KeyRequest: &keyRequest, CA: &CAConfig, } // Generate a self-signed certificate from the request. encodedCertFromCode, _, err := CreateSelfSignedCert(request) checkError(err, t) // Now compare to a pre-made certificate made using a JSON file with the // same request information. This JSON file is located in testdata/initCA // and is called ca_csr.json. CLIOutputFile := preMadeOutput CLIOutput, err := ioutil.ReadFile(CLIOutputFile) checkError(err, t) encodedCertFromCLI, err := cleanCLIOutput(CLIOutput, "cert") checkError(err, t) certFromCode, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCode) checkError(err, t) certFromCLI, err := helpers.ParseSelfSignedCertificatePEM(encodedCertFromCLI) checkError(err, t) // Nullify any fields of the certificates which are dependent upon the time // of the certificate's creation. nullifyTimeDependency(certFromCode) nullifyTimeDependency(certFromCLI) if !reflect.DeepEqual(certFromCode, certFromCLI) { unequalFields := checkFields( *certFromCode, *certFromCLI, reflect.TypeOf(*certFromCode)) t.Log("The following fields were unequal:") for _, field := range unequalFields { t.Log(field) } t.Fatal("Certificates unequal.") } }