From b5d67c733a52858115aad3a683552be0e146ceaf Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Tue, 17 Mar 2015 10:17:21 -0400 Subject: [PATCH 1/3] Addressing JCJ comments --- test/js/acme-util.js | 5 +++++ test/js/crypto-util.js | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/test/js/acme-util.js b/test/js/acme-util.js index 151e37c76..d76369893 100644 --- a/test/js/acme-util.js +++ b/test/js/acme-util.js @@ -1,3 +1,8 @@ +// Copyright 2014 ISRG. All rights reserved +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + module.exports = { fromStandardB64: function(x) { diff --git a/test/js/crypto-util.js b/test/js/crypto-util.js index dcc9854ca..a80c5de9e 100644 --- a/test/js/crypto-util.js +++ b/test/js/crypto-util.js @@ -1,3 +1,8 @@ +// Copyright 2014 ISRG. All rights reserved +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + var crypto = require("crypto"); var forge = require("node-forge"); var util = require("./acme-util.js"); From 34da176328d3249539311c4d2f97db4977749c77 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Tue, 17 Mar 2015 11:29:01 -0400 Subject: [PATCH 2/3] Use remote signer in CA testing --- ca/certificate-authority_test.go | 233 ++++++++++++++++++++++++------- 1 file changed, 186 insertions(+), 47 deletions(-) diff --git a/ca/certificate-authority_test.go b/ca/certificate-authority_test.go index 1a7d7c713..7575ea484 100644 --- a/ca/certificate-authority_test.go +++ b/ca/certificate-authority_test.go @@ -7,10 +7,16 @@ package ca import ( "crypto/x509" + "encoding/asn1" "encoding/hex" "encoding/pem" + "net/http" "testing" + "time" + apisign "github.com/cloudflare/cfssl/api/sign" + "github.com/cloudflare/cfssl/auth" + "github.com/cloudflare/cfssl/config" "github.com/cloudflare/cfssl/signer/local" _ "github.com/mattn/go-sqlite3" @@ -108,24 +114,109 @@ var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" + // * Random public key // * CN = example.com // * DNSNames = example.com, www.example.com -var CSR_HEX = "308202953082017d0201003016311430120603" + - "550403130b6578616d706c652e636f6d30820122300d06092a864886f70d0101010500038201" + - "0f003082010a0282010100baaf16e891828470cad87b849a73356f65e20ad3699fd5583a7200" + - "e924512d9eeb1dbe16441ad7bd804fa2e5726a06f0af5279012fe6354a5677259f5591984aa9" + - "99b8ea3ea10fbd5ecfa30e5f563b41c419374decfc98ea62c611046ad011c326470a2426f46d" + - "be6cc44fae3b247e19710810585f9f3ad7f64b2f305aebb72e2829866f89b20b03a300b7ff5f" + - "4e6204f41420d9fa731252692cee8e616636723abe8a7053fd86e2673190fa8b618ada5bc735" + - "ba57a145af86904a8f55a288d4d6ba9e501530f23f197f5b623443193fc92b7f87d6abbf740d" + - "9fc92800c7e0e1484d5eec6ffae1007c139c1ec19d67e749743fe8d8396fe190cfbcf2f90e05" + - "230203010001a03a303806092a864886f70d01090e312b302930270603551d110420301e820b" + - "6578616d706c652e636f6d820f7777772e6578616d706c652e636f6d300d06092a864886f70d" + - "01010b05000382010100514c622dc866b31c86777a26e9b2911618ce5b188591f08007b42772" + - "3497b733676a7d493c434fc819b8089869442fd299aa99ff7f7b9df881843727f0c8b89ca62a" + - "f8a12b38c963e9210148c4e1c0fc964aef2605f88ed777e6497d2e43e9a9713835d1ae96260c" + - "ca826c34c7ae52c77f5d8468643ee1936eadf04e1ebf8bbbb68b0ec7d0ef694432451292e4a3" + - "1989fd8339c07e01e04b6dd3834872b828d3f5b2b4dadda0596396e15fbdf446998066a74873" + - "2baf53f3f7ebb849e83cf734753c35ab454d1b62e1741a6514c5c575c0c805b4d668fcf71746" + - "ef32017613a52d6b807e2977f4fbc0a88b2e263347c4d9e35435333cf4f8288be53df41228ec" +var CN_AND_SAN_CSR_HEX = "308202a130820189020100301a311830160603550403130f6e6f742d6578" + + "616d706c652e636f6d30820122300d06092a864886f70d01010105000382" + + "010f003082010a0282010100e56ccbe37003c150202e6f543f9eb1d0e590" + + "76ac7f1f62654fa82fe131a23c66bd53a2f62ff7852015c84a394e36836d" + + "2018eba278e0740c85c4c6102787400c2ef069b4a72e6eb8ad8d1da5d76b" + + "f3e70dafc126578ed28cf40030e7fe5b5307ef630254726c639561b5445d" + + "372847bdb02576aa3622a688158c6af09d3938dbeba4d670cec4325be73a" + + "fa52a0a04dcba2f335f1e85020704db94ca125dce70b3209294c6c46ed4b" + + "48b95d8d51ae2d2fd227116023a48ca7381e35fd302ad2999df625a4b5ee" + + "82a0d0fefa88ac6a62b01674de75637ef83328202cda9930947d932000b0" + + "e53b82e099ab60fec9c8b6d4eccdee508b6ebca7e6ca3f752046c8350203" + + "010001a042304006092a864886f70d01090e31333031302f0603551d1104" + + "283026820f6e6f742d6578616d706c652e636f6d82137777772e6e6f742d" + + "6578616d706c652e636f6d300d06092a864886f70d01010b050003820101" + + "008c4bf2ab4dfd28d768697eecc5be889a6275287c7dd24f9232ffad5675" + + "de708c9cc911545d0e84f61b6584c5e237915bbf231d6518e7e228be2e65" + + "b4d50bd9729ce9e6aee00482e014de4edd4b9a4f9a7777b8943ef3512dbf" + + "940ac561c25b34ded9db1074136b978a65943ab1259608fb8109e008eac6" + + "23d7b29b2f1fad3a8e358aa070ead688016d9efed6da43412b136903de07" + + "137462d3f9203a344d84d7eb336999004e7e9972d5176001e2792f206e6c" + + "7c70b86d312459f21751d29ea53b41f9d02a229f9d7615b2a7ac83e849d0" + + "d0d9f8a08f8d7ba23295e77c95bc060c9227bfec0afb8c898e33c89903d7" + + "bbde4cf059dcc3e6c4ae4eef207c499d62" + +// CSR generated by Go: +// * Random public key +// * CN = not-example.com +// * DNSNames = [none] +var NO_SAN_CSR_HEX = "3082025f30820147020100301a311830160603550403130f6e6f742d6578" + + "616d706c652e636f6d30820122300d06092a864886f70d01010105000382" + + "010f003082010a0282010100aa6e56ff24906f93b855e7871dc8411a3cf7" + + "678d9563627e8ca37ab17dfe814ef7f828d6aa92b717f0da9df56990b953" + + "989d5afc3f2dddacd2b504b89782b49e55a04a64a4370d8ab1b2688f2596" + + "98132e5ce536f812ef5eb13824a922bbb89e30d6f2cace77462b9e65264a" + + "32320a7b348f9903b16640bc8c1c5f1208c6b456fd85bfa96ee9b7642c68" + + "3ab05b142d249525a730b230b39f2ba8d6f253263b5c3948b1a3d8a3467f" + + "7cfcdd1fdd6bff7828fda12784fd277be8c680fcdf2cc4676acff5df759f" + + "f4bc712ee1a560157233cbf6bb4bcb91dd1c5d2824b42f4913e4715c1ba4" + + "001fde0d90c274bfa81a79e4a0d00a7ddcbfdd8de4183b497487a20d0203" + + "010001a000300d06092a864886f70d01010b050003820101000ead204cfd" + + "45d307dd49de6937d7e2d8abf17490a49a8cee5250ef7799ef53229f8cfc" + + "735b9f65d789f898945f3d5536a09932e241050bd5473c47a4ac2493707f" + + "1142bf9a06d047384ad463463acb3744d435b4cff8c8b0f9673e8700e13b" + + "6bc99a486823fa85f7707e1bb8430e62541715ab6cb3fae3efb8356042a5" + + "c9f493dd08eff690570cce65cffc4fe354aa40957dc16a37a833aa968f62" + + "693d5059d53f6a96a159195d3fb7b558d462de63d945d4e3680d2b1f2c98" + + "33c3bfd92a9235de3d345a431ee5a675e0e18308bd2729413acd84432da4" + + "2410e1b87ae70227dd9a98e49ee6aeea9eaff67f968691918201e94697f2" + + "da010d6f939cea40c26038" + +// CSR generated by Go: +// * Random public key +// * C = US +// * CN = [none] +// * DNSNames = not-example.com +var NO_CN_CSR_HEX = "3082027f30820167020100300d310b300906035504061302555330820122" + + "300d06092a864886f70d01010105000382010f003082010a0282010100d8" + + "b3c11610ce17614f6d78de3f079db430e479c38978da8cd625b7c70dd445" + + "57fd99b9831693e6b9b09fb7c74a82058a1f1a4e1e087f04f93aa73bc35a" + + "688440205a6f5fd56ff478c5554b14c3b2a1a0b5eed1aef7189ad848e117" + + "04b1eb6c29b47ada40a5719a38ce2f2869896bf5405c2bafd4c7dfb99c0e" + + "9f26f80145e16b73bbacf67aedcd3b7ce57bb5b67cf692aec7956d23c236" + + "2336c2408b65469630dccca3ca006f28e36ca8c95dda84b6586f29c8de63" + + "661c09b58253e386a74707394cbba4de165f2745a65b717b9fd4b8b84c09" + + "85583b5c17d3e88bbf71c88eeeccb5d552d61cde7835ec83d6ec9b41114a" + + "0583f8eeae8a536cb3ca5786c22ab30203010001a02d302b06092a864886" + + "f70d01090e311e301c301a0603551d1104133011820f6e6f742d6578616d" + + "706c652e636f6d300d06092a864886f70d01010b05000382010100430239" + + "8db6b64b94d93399db32335232967ca6a748048483db8cb2b387871f758c" + + "6f7bf1593624b142127847cd2a511897bbadd8ad038468fb309fa2161031" + + "949b9ba24931b0d363ad2f8dae56a4c908ba748d41c664aa129dcb1a6f88" + + "0b90502cd244d9abd8dd5e78f763730660655a350f1c25af95cf1f89dda9" + + "076f4e6b84b6da9a98ed87f538624e4338fa0ff1a404e763dd6800694a21" + + "d28595927606308aefa1ac7e8f5600b05e33c0a7b25d3a9f5032c7c25264" + + "026c039733b179315254af4f25e90a1d00facd69313b36fdc66a5818fb49" + + "a0d90e0745d66a82d337289c9968b3ec4a4826c530c758cacecc18e06366" + + "dd8962c451c3ce22c2aed33726" + +// CSR generated by Go: +// * Random public key +// * C = US +// * CN = [none] +// * DNSNames = [none] +var NO_NAME_CSR_HEX = "308202523082013a020100300d310b300906035504061302555330820122" + + "300d06092a864886f70d01010105000382010f003082010a0282010100bc" + + "fae49f68f02c42500b2faf251628ee19e8ef048a35fef311c9c419c80606" + + "ab37340ad6e25cf4cc63c0283994b4ba705d86950ad5298094e0b9684647" + + "8d67abc695741317b4ff8da9fd33120342559cfdaf9109ac403f0d0bf9ff" + + "54dd79fa2256b218a9bdb17c608167c7fcad4cf839733c7eab9589fe6137" + + "e99bb24c24b7eb74e19f51ffee4ea62c4ab756f099ff5197c5032f60edff" + + "36022b8a99d35aeb706854fa9a31ea8a362a2251f08b93023b32e1df771a" + + "970f08a30ced656950b8ef71600d65d6995a0b92903b179c05a76f702a08" + + "0b41402c308d8ab57f14b5516b89fe317e38e13d7adad7f7025743610881" + + "9fb60268f0773b08b62ac8c8c84f2d0203010001a000300d06092a864886" + + "f70d01010b050003820101001eda9ce8253e8b933348851acd38ab63cd64" + + "f833d7ffc711f1b6e6a37a7deb7ad44b5589d90533ed61dfd48cab2775e2" + + "a19c41f5cb69faa9dde856606822a3bf798381836214154c17bc037f23ad" + + "67c84d876855c0aea871dc55bd14b2cd267e49b734bc7a38c29c334611bf" + + "ec7efdc56a1512e25fd12ca99a5809b1b6a808caf6a8baefff7fb2bda454" + + "5c226849674900ce7a1f90287ab31be80a4e2b6d64765b9d973628e60299" + + "6423edd74e7a58005bd520d4173f0c30d935de530477480d7725d9758f9a" + + "58c004d9e1e55af59ea517dfbd2bccca58216d8130b9f77c90328b2aa54b" + + "1778a629b584f2bc059489a236131de9b444adca90218c31a499a485" func TestIssueCertificate(t *testing.T) { // Decode pre-generated values @@ -135,44 +226,92 @@ func TestIssueCertificate(t *testing.T) { caCertPEM, _ := pem.Decode([]byte(CA_CERT_PEM)) caCert, _ := x509.ParseCertificate(caCertPEM.Bytes) - csrDER, _ := hex.DecodeString(CSR_HEX) - csr, _ := x509.ParseCertificateRequest(csrDER) + // Uncomment to create a CFSSL local signer - // Create a CFSSL local signer - signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, nil) + // CFSSL config + hostPort := "localhost:9000" + authKey := "79999d86250c367a2b517a1ae7d409c1" + profileName := "ee" // Create an SA sa, err := sa.NewSQLStorageAuthority("sqlite3", ":memory:") test.AssertNotError(t, err, "Failed to create SA") sa.InitTables() + // Create an online CFSSL instance + // This is designed to mimic what LE plans to do + authHandler, err := auth.New(authKey, nil) + test.AssertNotError(t, err, "Failed to create authentication handler") + policy := &config.Signing{ + Profiles: map[string]*config.SigningProfile{ + profileName: &config.SigningProfile{ + Usage: []string{"server auth"}, + CA: false, + IssuerURL: []string{"http://not-example.com/issuer-url"}, + OCSP: "http://not-example.com/ocsp", + CRL: "http://not-example.com/crl", + + Policies: []asn1.ObjectIdentifier{ + asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1}, + }, + Expiry: 8760 * time.Hour, + Backdate: time.Hour, + Provider: authHandler, + }, + }, + Default: &config.SigningProfile{ + Expiry: time.Hour, + }, + } + signer, err := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, policy) + test.AssertNotError(t, err, "Failed to create signer") + signHandler, err := apisign.NewAuthHandlerFromSigner(signer) + test.AssertNotError(t, err, "Failed to create signing API endpoint") + http.Handle("/api/v1/cfssl/authsign", signHandler) + // This goroutine should get killed when main() return + go (func() { http.ListenAndServe(hostPort, nil) })() + // Create a CA + // Uncomment to test with a remote signer + ca, err := NewCertificateAuthorityImpl(hostPort, authKey, profileName) + test.AssertNotError(t, err, "Failed to create CA") + ca.SA = sa + /* - // Uncomment to test with a remote signer - ca, err := NewCertificateAuthorityImpl("localhost:9000", "79999d86250c367a2b517a1ae7d409c1", "ee") - test.AssertNotError(t, err, "Failed to create CA") - ca.SA = sa + // Uncomment to test with a local signer + signer, _ := local.NewSigner(caKey, caCert, x509.SHA256WithRSA, nil) + ca := CertificateAuthorityImpl{ + Signer: signer, + SA: sa, + } */ - ca := CertificateAuthorityImpl{ - Signer: signer, - SA: sa, + + csrs := []string{CN_AND_SAN_CSR_HEX, NO_SAN_CSR_HEX, NO_CN_CSR_HEX} + for _, csrHEX := range csrs { + csrDER, _ := hex.DecodeString(csrHEX) + csr, _ := x509.ParseCertificateRequest(csrDER) + + // Sign CSR + certObj, err := ca.IssueCertificate(*csr) + test.AssertNotError(t, err, "Failed to sign certificate") + + // Verify cert contents + cert, err := x509.ParseCertificate(certObj.DER) + test.AssertNotError(t, err, "Certificate failed to parse") + + test.AssertEquals(t, cert.Subject.CommonName, "not-example.com") + + if len(cert.DNSNames) == 0 || cert.DNSNames[0] != "not-example.com" { + // NB: This does not check for www.not-example.com in the 'both' case + t.Errorf("Improper list of domain names %v", cert.DNSNames) + } + + if len(cert.Subject.Country) > 0 { + t.Errorf("Subject contained unauthorized values") + } + + // Verify that the cert got stored in the DB + _, err = sa.GetCertificate(certObj.ID) + test.AssertNotError(t, err, "Certificate not found in database") } - - // Sign CSR - certObj, err := ca.IssueCertificate(*csr) - test.AssertNotError(t, err, "Failed to sign certificate") - - // Verify cert contents - cert, err := x509.ParseCertificate(certObj.DER) - test.AssertNotError(t, err, "Certificate failed to parse") - - test.AssertEquals(t, cert.Subject.CommonName, "example.com") - - if len(cert.DNSNames) != 2 || cert.DNSNames[0] != "example.com" || cert.DNSNames[1] != "www.example.com" { - t.Errorf("Improper list of domain names %v", cert.DNSNames) - } - - // Verify that the cert got stored in the DB - _, err = sa.GetCertificate(certObj.ID) - test.AssertNotError(t, err, "Certificate not found in database") } From 74bbea6920147853ad471d08606f01979b99cb35 Mon Sep 17 00:00:00 2001 From: Richard Barnes Date: Tue, 17 Mar 2015 11:31:54 -0400 Subject: [PATCH 3/3] Test coverage for the no-name case --- ca/certificate-authority_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ca/certificate-authority_test.go b/ca/certificate-authority_test.go index 7575ea484..9212e010a 100644 --- a/ca/certificate-authority_test.go +++ b/ca/certificate-authority_test.go @@ -314,4 +314,12 @@ func TestIssueCertificate(t *testing.T) { _, err = sa.GetCertificate(certObj.ID) test.AssertNotError(t, err, "Certificate not found in database") } + + // Test that the CA rejects CSRs with no names + csrDER, _ := hex.DecodeString(NO_NAME_CSR_HEX) + csr, _ := x509.ParseCertificateRequest(csrDER) + _, err = ca.IssueCertificate(*csr) + if err == nil { + t.Errorf("CA improperly agreed to create a certificate with no name") + } }