diff --git a/ca/certificate-authority_test.go b/ca/certificate-authority_test.go index 73b0a1baf..9212e010a 100644 --- a/ca/certificate-authority_test.go +++ b/ca/certificate-authority_test.go @@ -7,14 +7,19 @@ 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" - "github.com/letsencrypt/boulder/policy" "github.com/letsencrypt/boulder/sa" "github.com/letsencrypt/boulder/test" ) @@ -105,38 +110,113 @@ var CA_CERT_PEM = "-----BEGIN CERTIFICATE-----\n" + "8jcQV9i1MJFGXV7k3En0lQv2z5AD9aFtkc6UjHpAzB8xEWMO0ZAtBg==\n" + "-----END CERTIFICATE-----" +// CSR generated by Go: +// * Random public key +// * CN = example.com +// * DNSNames = example.com, www.example.com +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 CSR_HEX = "3082028c30820174020100301a311830160603550403130f" + - "6e6f742d6578616d706c652e636f6d30820122300d06092a" + - "864886f70d01010105000382010f003082010a0282010100" + - "aac67dd1e11fae980048b0ac91be005f21d9df8bb38461cc" + - "a7dfad601a00e91ae488c240a03ec53a5752a33d837d2d9c" + - "357c6a99ea7e55fe75482524480bb367aa85f75541bd0284" + - "ede1ab9b54925a5c9f88d08f9dc857ee707a59d3503b31ea" + - "64e42099acd70d2204c872ef49983e44cc2bc24389159fc5" + - "f6ca41b80540fb7a2fbf8aa43af7f539782f20f185d416cc" + - "66a88e5f8913a292b4a217e5b12e8244a9686af3b49ac88b" + - "215c6eb097c4befa3e66257a1358791e2bc471c18ba2ca6e" + - "161d2dcb53ebcb06e6b4b2e6cd42ff970581bc4971009cbd" + - "7ccc3f89648db720e2908a1be613a9c3afb46b477261c1bc" + - "c057bc749a102e6bd9dc45d87b2d97c50203010001a02d30" + - "2b06092a864886f70d01090e311e301c301a0603551d1104" + - "133011820f6e6f742d6578616d706c652e636f6d300d0609" + - "2a864886f70d01010b05000382010100a37025c2cb88b4fa" + - "f3c8417820a78a069b92cef45a3d2f3fbd18f41a07128258" + - "38bc55e6c1c416e5f34c365924391294741c23657ffa77e4" + - "aa3d589b560cbb9156aae175637cbb5061d69eefa7f432ca" + - "c9e4d03feaa367954cf6986a72ca76307c01852db72b43ae" + - "5ab7f673b81b58e06d8af1f681cd7c88d2fbc8c80d592a3f" + - "7c3ea20035b73c8e6afc8daea4d168fe469f7da9e4bac660" + - "fc207d1d93dce118dc7381e69fa4af37bb4d4d6d5342fa55" + - "7798a363aa04cf350ad1748e96eabee04fa379dd98524ea1" + - "53f07e1654e6077f4aaaf5c5b27edaf0385b48e0fc281424" + - "6363a01370c89e666169276eb133731cff2379d46d2fff9d" + - "f277b6d23fa24f9b" +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 @@ -146,45 +226,100 @@ 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, - PA: policy.NewPolicyAuthorityImpl(), + + 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, "not-example.com") - - if len(cert.DNSNames) != 1 || cert.DNSNames[0] != "not-example.com" { - t.Errorf("Improper list of domain names %v", cert.DNSNames) + // 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") } - - // Verify that the cert got stored in the DB - _, err = sa.GetCertificate(certObj.ID) - test.AssertNotError(t, err, "Certificate not found in database") } 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");