123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- package csr
- import (
- "crypto"
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rsa"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/asn1"
- "encoding/pem"
- "io/ioutil"
- "testing"
- "github.com/cloudflare/cfssl/errors"
- "github.com/cloudflare/cfssl/helpers"
- )
- //TestNew validate the CertificateRequest created to return with a BasicKeyRequest
- //in KeyRequest field
- func TestNew(t *testing.T) {
- if cr := New(); cr.KeyRequest == nil {
- t.Fatalf("Should create a new, empty certificate request with BasicKeyRequest")
- }
- }
- // TestBasicKeyRequest ensures that key generation returns the same type of
- // key specified in the BasicKeyRequest.
- func TestBasicKeyRequest(t *testing.T) {
- kr := NewBasicKeyRequest()
- priv, err := kr.Generate()
- if err != nil {
- t.Fatalf("%v", err)
- }
- switch priv.(type) {
- case *rsa.PrivateKey:
- if kr.Algo() != "rsa" {
- t.Fatal("RSA key generated, but expected", kr.Algo())
- }
- case *ecdsa.PrivateKey:
- if kr.Algo() != "ecdsa" {
- t.Fatal("ECDSA key generated, but expected", kr.Algo())
- }
- }
- }
- // TestPKIXName validates building a pkix.Name structure from a
- // CertificateRequest.
- func TestPKIXName(t *testing.T) {
- var cr = &CertificateRequest{
- CN: "Test Common Name",
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare, Inc.",
- OU: "Systems Engineering",
- },
- {
- C: "GB",
- ST: "London",
- L: "London",
- O: "CloudFlare, Inc",
- OU: "Systems Engineering",
- },
- },
- Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
- KeyRequest: NewBasicKeyRequest(),
- }
- name := cr.Name()
- if len(name.Country) != 2 {
- t.Fatal("Expected two countries in SubjInfo.")
- } else if len(name.Province) != 2 {
- t.Fatal("Expected two states in SubjInfo.")
- } else if len(name.Locality) != 2 {
- t.Fatal("Expected two localities in SubjInfo.")
- } else if len(name.Country) != 2 {
- t.Fatal("Expected two countries in SubjInfo.")
- } else if len(name.Organization) != 2 {
- t.Fatal("Expected two organization in SubjInfo.")
- } else if len(name.OrganizationalUnit) != 2 {
- t.Fatal("Expected two organizational units in SubjInfo.")
- }
- }
- // TestParseRequest ensures that a valid certificate request does not
- // error.
- func TestParseRequest(t *testing.T) {
- var cr = &CertificateRequest{
- CN: "Test Common Name",
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare, Inc.",
- OU: "Systems Engineering",
- },
- {
- C: "GB",
- ST: "London",
- L: "London",
- O: "CloudFlare, Inc",
- OU: "Systems Engineering",
- },
- },
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
- KeyRequest: NewBasicKeyRequest(),
- Extensions: []pkix.Extension{
- pkix.Extension{
- Id: asn1.ObjectIdentifier{1, 2, 3, 4, 5},
- Value: []byte("AgEB"),
- },
- },
- }
- csrBytes, _, err := ParseRequest(cr)
- if err != nil {
- t.Fatalf("%v", err)
- }
- block, _ := pem.Decode(csrBytes)
- if block == nil {
- t.Fatalf("%v", err)
- }
- if block.Type != "CERTIFICATE REQUEST" {
- t.Fatalf("Incorrect block type: %s", block.Type)
- }
- csr, err := x509.ParseCertificateRequest(block.Bytes)
- if err != nil {
- t.Fatalf("%v", err)
- }
- found := false
- for _, ext := range csr.Extensions {
- if ext.Id.Equal(asn1.ObjectIdentifier{1, 2, 3, 4, 5}) {
- found = true
- break
- }
- }
- if !found {
- t.Fatalf("CSR did not include Custom Extension")
- }
- }
- // TestParseRequestCA ensures that a valid CA certificate request does not
- // error and the resulting CSR includes the BasicConstraint extension
- func TestParseRequestCA(t *testing.T) {
- var cr = &CertificateRequest{
- CN: "Test Common Name",
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare, Inc.",
- OU: "Systems Engineering",
- },
- {
- C: "GB",
- ST: "London",
- L: "London",
- O: "CloudFlare, Inc",
- OU: "Systems Engineering",
- },
- },
- CA: &CAConfig{
- PathLength: 0,
- PathLenZero: true,
- },
- KeyRequest: NewBasicKeyRequest(),
- }
- csrBytes, _, err := ParseRequest(cr)
- if err != nil {
- t.Fatalf("%v", err)
- }
- block, _ := pem.Decode(csrBytes)
- if block == nil {
- t.Fatalf("%v", err)
- }
- if block.Type != "CERTIFICATE REQUEST" {
- t.Fatalf("Incorrect block type: %s", block.Type)
- }
- csr, err := x509.ParseCertificateRequest(block.Bytes)
- if err != nil {
- t.Fatalf("%v", err)
- }
- found := false
- for _, ext := range csr.Extensions {
- if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
- found = true
- break
- }
- }
- if !found {
- t.Fatalf("CSR did not include BasicConstraint Extension")
- }
- }
- // TestParseRequestCANoPathlen ensures that a valid CA certificate request
- // with an unspecified pathlen does not error and the resulting CSR includes
- // the BasicConstraint extension
- func TestParseRequestCANoPathlen(t *testing.T) {
- var cr = &CertificateRequest{
- CN: "Test Common Name",
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare, Inc.",
- OU: "Systems Engineering",
- },
- {
- C: "GB",
- ST: "London",
- L: "London",
- O: "CloudFlare, Inc",
- OU: "Systems Engineering",
- },
- },
- CA: &CAConfig{
- PathLength: 0,
- PathLenZero: false,
- },
- KeyRequest: NewBasicKeyRequest(),
- }
- csrBytes, _, err := ParseRequest(cr)
- if err != nil {
- t.Fatalf("%v", err)
- }
- block, _ := pem.Decode(csrBytes)
- if block == nil {
- t.Fatalf("%v", err)
- }
- if block.Type != "CERTIFICATE REQUEST" {
- t.Fatalf("Incorrect block type: %s", block.Type)
- }
- csr, err := x509.ParseCertificateRequest(block.Bytes)
- if err != nil {
- t.Fatalf("%v", err)
- }
- found := false
- for _, ext := range csr.Extensions {
- if ext.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
- bc := &BasicConstraints{}
- asn1.Unmarshal(ext.Value, bc)
- if bc.IsCA == true && bc.MaxPathLen == -1 {
- found = true
- break
- }
- }
- }
- if !found {
- t.Fatalf("CSR did not include BasicConstraint Extension")
- }
- }
- func whichCurve(sz int) elliptic.Curve {
- switch sz {
- case 256:
- return elliptic.P256()
- case 384:
- return elliptic.P384()
- case 521:
- return elliptic.P521()
- }
- return nil
- }
- // TestECGeneration ensures that the proper curve is used depending on
- // the bit size specified in a key request and that an appropriate
- // signature algorithm is returned.
- func TestECGeneration(t *testing.T) {
- var eckey *ecdsa.PrivateKey
- for _, sz := range []int{256, 384, 521} {
- kr := &BasicKeyRequest{"ecdsa", sz}
- priv, err := kr.Generate()
- if err != nil {
- t.Fatalf("%v", err)
- }
- eckey = priv.(*ecdsa.PrivateKey)
- if eckey.Curve != whichCurve(sz) {
- t.Fatal("Generated key has wrong curve.")
- }
- if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
- t.Fatal("Invalid signature algorithm!")
- }
- }
- }
- func TestRSAKeyGeneration(t *testing.T) {
- var rsakey *rsa.PrivateKey
- for _, sz := range []int{2048, 3072, 4096} {
- kr := &BasicKeyRequest{"rsa", sz}
- priv, err := kr.Generate()
- if err != nil {
- t.Fatalf("%v", err)
- }
- rsakey = priv.(*rsa.PrivateKey)
- if rsakey.PublicKey.N.BitLen() != kr.Size() {
- t.Fatal("Generated key has wrong size.")
- }
- if sa := kr.SigAlgo(); sa == x509.UnknownSignatureAlgorithm {
- t.Fatal("Invalid signature algorithm!")
- }
- }
- }
- // TestBadBasicKeyRequest ensures that generating a key from a BasicKeyRequest
- // fails with an invalid algorithm, or an invalid RSA or ECDSA key
- // size. An invalid ECDSA key size is any size other than 256, 384, or
- // 521; an invalid RSA key size is any size less than 2048 bits.
- func TestBadBasicKeyRequest(t *testing.T) {
- kr := &BasicKeyRequest{"yolocrypto", 1024}
- if _, err := kr.Generate(); err == nil {
- t.Fatal("Key generation should fail with invalid algorithm")
- } else if sa := kr.SigAlgo(); sa != x509.UnknownSignatureAlgorithm {
- t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
- }
- kr.A = "ecdsa"
- if _, err := kr.Generate(); err == nil {
- t.Fatal("Key generation should fail with invalid key size")
- } else if sa := kr.SigAlgo(); sa != x509.ECDSAWithSHA1 {
- t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
- }
- kr.A = "rsa"
- if _, err := kr.Generate(); err == nil {
- t.Fatal("Key generation should fail with invalid key size")
- } else if sa := kr.SigAlgo(); sa != x509.SHA1WithRSA {
- t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
- }
- kr = &BasicKeyRequest{"tobig", 9216}
- kr.A = "rsa"
- if _, err := kr.Generate(); err == nil {
- t.Fatal("Key generation should fail with invalid key size")
- } else if sa := kr.SigAlgo(); sa != x509.SHA512WithRSA {
- t.Fatal("The wrong signature algorithm was returned from SigAlgo!")
- }
- }
- // TestDefaultBasicKeyRequest makes sure that certificate requests without
- // explicit key requests fall back to the default key request.
- func TestDefaultBasicKeyRequest(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
- }
- _, priv, err := ParseRequest(req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- // If the default key type changes, this will need to be changed.
- block, _ := pem.Decode(priv)
- if block == nil {
- t.Fatal("Bad private key was generated!")
- }
- DefaultKeyRequest := NewBasicKeyRequest()
- switch block.Type {
- case "RSA PRIVATE KEY":
- if DefaultKeyRequest.Algo() != "rsa" {
- t.Fatal("Invalid default key request.")
- }
- case "EC PRIVATE KEY":
- if DefaultKeyRequest.Algo() != "ecdsa" {
- t.Fatal("Invalid default key request.")
- }
- }
- }
- // TestRSACertRequest validates parsing a certificate request with an
- // RSA key.
- func TestRSACertRequest(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
- KeyRequest: &BasicKeyRequest{"rsa", 2048},
- }
- _, _, err := ParseRequest(req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- }
- // TestBadCertRequest checks for failure conditions of ParseRequest.
- func TestBadCertRequest(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
- KeyRequest: &BasicKeyRequest{"yolo-crypto", 2048},
- }
- _, _, err := ParseRequest(req)
- if err == nil {
- t.Fatal("ParseRequest should fail with a bad key algorithm.")
- }
- }
- // testValidator is a stripped-down validator that checks to make sure
- // the request has a common name. It should mimic some of the
- // functionality expected in an actual validator.
- func testValidator(req *CertificateRequest) error {
- if req.CN == "" {
- return errors.NewBadRequestMissingParameter("CN")
- }
- return nil
- }
- // TestGenerator ensures that a valid request is processed properly
- // and returns a certificate request and key.
- func TestGenerator(t *testing.T) {
- g := &Generator{testValidator}
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
- KeyRequest: &BasicKeyRequest{"rsa", 2048},
- }
- csrBytes, _, err := g.ProcessRequest(req)
- if err != nil {
- t.Fatal(err)
- }
- block, _ := pem.Decode([]byte(csrBytes))
- if block == nil {
- t.Fatalf("bad CSR in PEM")
- }
- if block.Type != "CERTIFICATE REQUEST" {
- t.Fatalf("bad CSR in PEM")
- }
- csr, err := x509.ParseCertificateRequest(block.Bytes)
- if err != nil {
- t.Fatal(err)
- }
- if len(csr.DNSNames) != 2 {
- t.Fatal("SAN parsing error")
- }
- if len(csr.IPAddresses) != 1 {
- t.Fatal("SAN parsing error")
- }
- if len(csr.EmailAddresses) != 1 {
- t.Fatal("SAN parsing error")
- }
- }
- // TestBadGenerator ensures that a request that fails the validator is
- // not processed.
- func TestBadGenerator(t *testing.T) {
- g := &Generator{testValidator}
- missingCN := &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- // Missing CN
- Hosts: []string{"cloudflare.com", "www.cloudflare.com"},
- KeyRequest: &BasicKeyRequest{"rsa", 2048},
- }
- _, _, err := g.ProcessRequest(missingCN)
- if err == nil {
- t.Fatalf("Request should have failed.")
- }
- }
- func TestWeakCSR(t *testing.T) {
- weakKey := &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "jdoe@example.com"},
- KeyRequest: &BasicKeyRequest{"rsa", 1024},
- }
- g := &Generator{testValidator}
- _, _, err := g.ProcessRequest(weakKey)
- if err == nil {
- t.Fatalf("Request should have failed.")
- }
- }
- var testEmpty = []struct {
- name Name
- ok bool
- }{
- {
- Name{},
- true,
- },
- {
- Name{C: "OK"},
- false,
- },
- {
- Name{ST: "OK"},
- false,
- },
- {
- Name{L: "OK"},
- false,
- },
- {
- Name{O: "OK"},
- false,
- },
- {
- Name{OU: "OK"},
- false,
- },
- }
- func TestIsNameEmpty(t *testing.T) {
- for i, c := range testEmpty {
- if IsNameEmpty(c.name) != c.ok {
- t.Fatalf("%d: expected IsNameEmpty to return %v, but have %v", i, c.ok, !c.ok)
- }
- }
- }
- func TestGenerate(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1", "jdoe@example.com"},
- KeyRequest: &BasicKeyRequest{"ecdsa", 256},
- }
- key, err := req.KeyRequest.Generate()
- if err != nil {
- t.Fatalf("%v", err)
- }
- priv, ok := key.(crypto.Signer)
- if !ok {
- t.Fatal("Private key is not a signer.")
- }
- csrPEM, err := Generate(priv, req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- csr, _, err := helpers.ParseCSR(csrPEM)
- if err != nil {
- t.Fatalf("%v", err)
- }
- if len(csr.DNSNames) != 2 {
- t.Fatal("SAN parsing error")
- }
- if len(csr.IPAddresses) != 1 {
- t.Fatal("SAN parsing error")
- }
- if len(csr.EmailAddresses) != 1 {
- t.Fatal("SAN parsing error")
- }
- }
- // TestReGenerate ensures Regenerate() is abel to use the provided CSR as a template for signing a new
- // CSR using priv.
- func TestReGenerate(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
- KeyRequest: &BasicKeyRequest{"ecdsa", 256},
- }
- _, key, err := ParseRequest(req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- priv, err := helpers.ParsePrivateKeyPEM(key)
- if err != nil {
- t.Fatalf("%v", err)
- }
- csr, err := Generate(priv, req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- if _, _, err = helpers.ParseCSR(csr); err != nil {
- t.Fatalf("%v", err)
- }
- _, err = Regenerate(priv, csr)
- if err != nil {
- t.Fatalf("%v", err)
- }
- }
- // TestBadReGenerator ensures that a request that fails the ParseCSR is
- // not processed.
- func TestBadReGenerate(t *testing.T) {
- var req = &CertificateRequest{
- Names: []Name{
- {
- C: "US",
- ST: "California",
- L: "San Francisco",
- O: "CloudFlare",
- OU: "Systems Engineering",
- },
- },
- CN: "cloudflare.com",
- Hosts: []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
- KeyRequest: &BasicKeyRequest{"ecdsa", 256},
- }
- _, key, err := ParseRequest(req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- priv, err := helpers.ParsePrivateKeyPEM(key)
- if err != nil {
- t.Fatalf("%v", err)
- }
- csr, err := Generate(priv, req)
- if err != nil {
- t.Fatalf("%v", err)
- }
- block := pem.Block{
- Type: "CERTIFICATE REQUEST",
- Headers: map[string]string{
- "Location": "UCSD",
- },
- Bytes: csr,
- }
- csr = pem.EncodeToMemory(&block)
- _, err = Regenerate(priv, csr)
- if err == nil {
- t.Fatalf("%v", err)
- }
- }
- var testECDSACertificateFile = "testdata/test-ecdsa-ca.pem"
- func TestExtractCertificateRequest(t *testing.T) {
- certPEM, err := ioutil.ReadFile(testECDSACertificateFile)
- if err != nil {
- t.Fatal(err)
- }
- // must parse ok
- cert, err := helpers.ParseCertificatePEM(certPEM)
- if err != nil {
- t.Fatal(err)
- }
- req := ExtractCertificateRequest(cert)
- if req.CN != "" {
- t.Fatal("Bad Certificate Request!")
- }
- if len(req.Names) != 1 {
- t.Fatal("Bad Certificate Request!")
- }
- name := req.Names[0]
- if name.C != "US" || name.ST != "California" || name.O != "CloudFlare, Inc." ||
- name.OU != "Test Certificate Authority" || name.L != "San Francisco" {
- t.Fatal("Bad Certificate Request!")
- }
- if req.CA == nil || req.CA.PathLength != 2 {
- t.Fatal("Bad Certificate Request!")
- }
- }
|